Skip to content

New feature and enhancement: Test titles, descriptions, tags and generics - #68

Draft
gmartina wants to merge 11 commits into
OSVVM:devfrom
gmartina:dev-i67
Draft

New feature and enhancement: Test titles, descriptions, tags and generics#68
gmartina wants to merge 11 commits into
OSVVM:devfrom
gmartina:dev-i67

Conversation

@gmartina

@gmartina gmartina commented Dec 26, 2025

Copy link
Copy Markdown

Summary

This PR enhances OSVVM report metadata and presentation across YAML, HTML, and JUnit XML outputs.

New metadata features

  • Test Title (display-only): Added test Title support (VHDL API + storage) with fallback-to-name behavior in HTML where a human-readable label is needed, while keeping the test Name as the stable identifier for filenames/anchors.
  • Test Suite Title (display-only): Added suite-level Title with the same “display vs identifier” split: suite Name remains the stable ID, suite Title is used for report display with fallback.
  • Suite Description / Suite Brief: Added suite-level description and brief support in build YAML and HTML.
  • Test Brief: Added/extended test brief management and ensured report behavior matches intent.
  • Test Tags: Added support for per-test tags (name/value pairs) to capture important test context such as configuration values, modes, key signals/parameters, or any other “this run matters because …” information you want visible in reports. Tags include optional visibility control (whether a tag appears in the Test Case Summary table columns vs only on the testcase page/details).

Report generation changes

  • YAML
    • Emits suite fields such as Title, Brief, Description when set.
    • Emits test fields such as Title, Brief, Description, Tags, plus tag visibility metadata.
    • Tag values in YAML are emitted as native scalars where possible (for example: integer, real, boolean) as well as strings (for example: integer values like burstlength: 256), so report generators can preserve type information.
  • HTML build reports
    • Shows Title (suite/test) where appropriate, with clean fallback to Name.
    • Conditionally renders Brief columns in suite/testcase summary tables only if at least one entry has an explicit Brief.
    • Adds styling improvements for readability:
      • “ —
        ” headings with a strong separator and de-emphasized suffix.
      • Prevents wrapping of long Titles in key first columns (suite and testcase summary tables) to avoid overly narrow columns.
  • HTML testcase pages
    • Adds Brief and testcase source filename into the testcase “Summary” table.
    • Uses Title (fallback to Name) consistently across headings.
    • Updates Alert section headings (Alert Report / Alert Settings / Alert Results) to follow the same heading styling.
    • Ensures Alert Results top-level row uses Title (fallback) while keeping child alert names unchanged.
  • JUnit XML
    • Adds title / brief properties when present.

Configuration & formatting utilities

  • Generics enhancement (columns): Testcase Generics can be shown as columns in the Test Case Summary table (so key configuration values are visible at a glance).
  • Configurable generic selection: Which Generics become columns is configurable (e.g., whitelist key generics you care about), with controls such as max-columns.
  • Added configuration APIs for controlling which Tags appear in Test Case Summary tables (including whitelists and max-columns).
  • Added scalar formatting helpers (including datatype inference) and HTML escaping improvements.
  • Added HTML enhancements such as datatype badges and elapsed time presentation (as applicable by report type).

VHDL API additions (OSVVM/AlertLogPkg.vhd)

  • Test Title API: SetTestTitle, GetTestTitle, ClearTestTitle.
  • Extended SetTestName: SetTestName(Name, Title => "...") to set a stable identifier plus an optional display title.
  • Test Brief API: SetTestBrief, GetTestBrief, ClearTestBrief.
  • Test Tags API: SetTestTag(TagName, TagValue, ShowInSummary => ...) overloads for common types (string/boolean/integer/time/real/std_logic), including control over whether each tag appears in summary tables.

Usage

TestSuite TestSuiteDemo
SetTestSuiteTitle "Demo Suite name"
SetTestSuiteBrief "Demonstrates suite-level descriptions (in the .pro file) and test-case descriptions/tags (in VHDL)"

# Test Case Summary: hide all generics except G_WIDTH
# If all Generics need to be shown, do not call SetTestCaseSummaryGenerics
SetTestCaseSummaryGenerics G_WIDTH
# Run the two test architectures
RunTest TestDescription_Demo1.vhd [generic G_WIDTH 32] [generic G_PERIOD "10ns"] [generic G_CFG1 TRUE ] [generic G_CFG2 FALSE]
RunTest TestDescription_Demo2.vhd [generic G_WIDTH 8 ] [generic G_PERIOD "5ns" ] [generic G_CFG1 FALSE] [generic G_CFG2 TRUE]
  -- Important test configuration signals/constants that need to be reported in the test case
  signal DataWidth    : natural := 8 ;
  signal BurstLength  : natural := 256 ;
  signal SyncRegs     : boolean := TRUE ;
  signal BufferEnable : boolean := FALSE ;
  constant delay_time : time := 100 ns ;
  signal cfg_real     : real := 3.14 ;
    -- Set test name to match the entity(architecture) name
    -- SetTestName("TestDescription_Demo1") ;
    SetTestName("TestDescription_Demo1", "Burst test without back-pressure") ;
    SetTestBrief("This is a short summary of TestDescription_Demo1") ;

    -- Set Test Description using Markdown subset
    SetTestDescription(
      "This demo shows how to document a test case using a *formatted* description." & LF &
      "The goal is to keep it readable in both YAML and HTML." & LF & LF &
      "## What this test does" & LF &
      "- Exercises a simple pass case" & LF &
      "- Demonstrates **bold** and *italic* emphasis" & LF &
      "- Demonstrates bullet lists" & LF &
      "- Demonstrates inline code like `SetTestTag(""Name"", Value)`" & LF &
      "- Demonstrates links like [OSVVM docs](https://osvvm.github.io)" & LF &
      "- Demonstrates links like [Other link](/home/user/local/path/example)" & LF & LF &
      "### Notes" & LF &
      "Use SetTestTag for structured metadata; use Description for narrative context." & LF &
      "Keep formatting simple and consistent." & LF & LF &
      "#### More heading levels" & LF &
      "This is a level-4 heading (####)." & LF &
      "#### Escapes for literals" & LF &
      "Use backslash escapes to show markup characters literally:" & LF &
        "- \* shows a literal asterisk: \*not italic\*" & LF &
        "- \# shows a literal hash: \#not a heading" & LF &
        "- \` shows a literal backtick: \`not code\`" & LF
    ) ;
    
    -- Set configuration tags as key-value pairs
    -- Tags are visible in the Test Case Summary table by default.
    -- Use the optional 3rd argument to hide less-important tags from the summary.
    SetTestTag("Cfg", "CFG_2", FALSE) ;
    SetTestTag("Scenario", "Maximum Burst", FALSE) ;
    SetTestTag("Priority", "Medium", FALSE) ;
    SetTestTag("Condition", "Back-pressure Active", FALSE) ;
    -- For consistency, the actual name and value can be passed through
    SetTestTag(DataWidth'simple_name, DataWidth, FALSE) ;
    SetTestTag(BurstLength'simple_name, BurstLength) ;
    SetTestTag(SyncRegs'simple_name, SyncRegs) ;
    SetTestTag(BufferEnable'simple_name, BufferEnable) ;
    SetTestTag(delay_time'simple_name, delay_time) ;
    SetTestTag(cfg_real'simple_name, cfg_real) ;

Screenshots

Test Suite Summary table:

test suite tables

Added test case summary table:

test case summary table

Markdown subset example:

test case description section

Added Generics table:

test case generics table

Added Tags table

test case tags table

Test case report

test case report

YAML Output:

#....
TestSuites: 
  - Name: TestSuiteDemo
    TestCases:
      - TestCaseName: "TestDescription_Demo1"
        FunctionalCoverage:  ""
        SimulationTime: "30000000 fs"
        Name: "TestDescription_Demo1"
        Status: PASSED
        Results: {TotalErrors: 0, AlertCount: {Failure: 0, Error: 0, Warning: 0}, PassedCount: 2, AffirmCount: 2, RequirementsPassed: 0, RequirementsGoal: 0, DisabledAlertCount: {Failure: 0, Error: 0, Warning: 0}, ExpectedCount: {Failure: 0, Error: 0, Warning: 0}}
        Title: "Burst test without back-pressure"
        Brief: "This is a short summary of TestDescription_Demo1"
        Description: "This demo shows how to document a test case using a *formatted* description.\nThe goal is to keep it readable in both YAML and HTML.\n\n## What this test does\n- Exercises a simple pass case\n- Demonstrates **bold** and *italic* emphasis\n- Demonstrates bullet lists\n- Demonstrates inline code like `SetTestTag(\"Name\", Value)`\n- Demonstrates links like [OSVVM docs](https://osvvm.github.io)\n- Demonstrates links like [Other link](/home/user/local/path/example)\n\n### Notes\nUse SetTestTag for structured metadata; use Description for narrative context.\nKeep formatting simple and consistent.\n\n#### More heading levels\nThis is a level-4 heading (####).\n#### Escapes for literals\nUse backslash escapes to show markup characters literally:\n- \\* shows a literal asterisk: \\*not italic\\*\n- \\# shows a literal hash: \\#not a heading\n- \\` shows a literal backtick: \\`not code\\`\n"
        Tags:
          Cfg: "CFG_2"
          Scenario: "Maximum Burst"
          Priority: "Medium"
          Condition: "Back-pressure Active"
          datawidth: 8
          burstlength: 256
          syncregs: true
          bufferenable: false
          delay_time: "100 ns"
          cfg_real: 3.14
        TagSummaryVisibility:
          Cfg: false
          Scenario: false
          Priority: false
          Condition: false
          datawidth: false
          burstlength: true
          syncregs: true
          bufferenable: true
          delay_time: true
          cfg_real: true
        TestCaseFileName: "TestDescription_Demo1_G_WIDTH_32_G_PERIOD_10ns_G_CFG1_TRUE_G_CFG2_FALSE"
        Generics:
          G_CFG1: true
          G_CFG2: false
          G_PERIOD: "10ns"
          G_WIDTH: 32
        ElapsedTime: 0.236
      - TestCaseName: "TestDescription_Demo2"
        FunctionalCoverage:  ""
        SimulationTime: "30000000 fs"
        Name: "TestDescription_Demo2"
        Status: PASSED
        Results: {TotalErrors: 0, AlertCount: {Failure: 0, Error: 0, Warning: 0}, PassedCount: 1, AffirmCount: 1, RequirementsPassed: 0, RequirementsGoal: 0, DisabledAlertCount: {Failure: 0, Error: 0, Warning: 0}, ExpectedCount: {Failure: 0, Error: 0, Warning: 0}}
        Title: "Corner Case 7 with Back-pressure"
        Brief: "This is a short summary. Corner Case 7 - Max Burst Length with Back-pressure"
        Description: "This demo2 shows how to document a test case using a *formatted* description.\nThe goal is to keep it readable in both YAML and HTML.\n\n## What this test does\n1. Exercises a simple pass case\n2. Demonstrates **bold** and *italic* emphasis\n3. Demonstrates bullet lists\n4. Demonstrates inline code like `EndOfTestReports`\n5. Demonstrates links like [Report index](../index.html)\n\n### Notes\nUse SetTestTag for structured metadata; use Description for narrative context.\nKeep formatting simple and consistent.\n\n#### More heading levels\nThis section uses #### and can include a link: [OSVVM docs](https://osvvm.github.io).\n#### Escapes\nEscaped literals: \\*not italic\\*, \\#not heading, and \\`not code\\`.\n"
        Tags:
          Configuration: "CFG_1"
          Scenario: "Maximum Burst"
          Priority: "Medium"
          Condition: "Back-pressure Active"
          datawidth: 64
          burstlength: 1024
          syncregs: false
          bufferenable: true
          delay_time: "20000 ns"
          cfg_real: 9.99
        TagSummaryVisibility:
          Configuration: false
          Scenario: false
          Priority: false
          Condition: false
          datawidth: false
          burstlength: true
          syncregs: true
          bufferenable: true
          delay_time: true
          cfg_real: true
        TestCaseFileName: "TestDescription_Demo2_G_WIDTH_8_G_PERIOD_5ns_G_CFG1_FALSE_G_CFG2_TRUE"
        Generics:
          G_CFG1: false
          G_CFG2: true
          G_PERIOD: "5ns"
          G_WIDTH: 8
        ElapsedTime: 0.192
    Title: "Demo Suite name"
    Brief: "Demonstrates suite-level descriptions (in the .pro file) and test-case descriptions/tags (in VHDL)"
    ElapsedTime: 0.602
 #....

Related PR

OSVVM/OSVVM#105

Related Issues

#67

- Introduced SetTestSuiteDescription and SetTestSuiteBrief procedures for setting descriptions and briefs for test suites.
- Updated YAML report generation to include brief and description fields.
- Enhanced HTML report generation to display brief information for test suites and test cases.
- Added utility functions for formatting YAML scalars and escaping HTML.
@Paebbels

Paebbels commented Dec 27, 2025

Copy link
Copy Markdown
Member

@gmartina I had a first round of discussions with @JimLewis and we're both very impressed by the size and complexity of the change: modifying VHDL, taking care of TCL code, modifying the YAML, XML and HTML reports, etc.

The contribution is very powerful and adds lots of capabilities to OSVVM. Especially as reports are one of the strongest features of OSVVM compared to other frameworks.


Your code example uses SetTestDescription, but it's not in the description text. I assume you also added VHDL procedures for descriptions too, right?

I have 3 modification requests for the YAML format:

  • The YAML version field should be incremented in the minor version (1.1?)
    This can be done by @JimLewis when he merges and finalizes the code before merging to main.

  • Description should be written as a multi-line string without embedded escape sequences for linebreaks. This enhances readability even within the YAML file, but not loosing any information:

    TestSuites: 
      - Name: TestSuiteDemo
        TestCases:
          - TestCaseName: "TestDescription_Demo1"
            Description: "This demo shows how to document a test case using a *formatted* description.\nThe goal is to keep it readable in both YAML and HTML.\n\n## What this test does\n- Exercises a simple pass case\n- Demonstrates **bold** and *italic* emphasis\n- Demonstrates bullet lists\n- Demonstrates inline code like `SetTestTag("Name", Value)`\n- Demonstrates links like [OSVVM docs](https://osvvm.github.io)\n- Demonstrates links like [Other link](/home/user/local/path/example)\n\n### Notes\nUse SetTestTag for structured metadata; use Description for narrative context.\nKeep formatting simple and consistent.\n\n#### More heading levels\nThis is a level-4 heading (####).\n#### Escapes for literals\nUse backslash escapes to show markup characters literally:\n- \\* shows a literal asterisk: \\*not italic\\*\n- \\# shows a literal hash: \\#not a heading\n- \\` shows a literal backtick: \\`not code\\`\n"

    Preferred output:

    TestSuites: 
      - Name: TestSuiteDemo
        TestCases:
          - TestCaseName: "TestDescription_Demo1"
            Description: |
              This demo shows how to document a test case using a *formatted* description.
              The goal is to keep it readable in both YAML and HTML.
              
              ## What this test does
              - Exercises a simple pass case
              - Demonstrates **bold** and *italic* emphasis
              - Demonstrates bullet lists
              - Demonstrates inline code like `SetTestTag(\"Name\", Value)`
              - Demonstrates links like [OSVVM docs](https://osvvm.github.io)
              - Demonstrates links like [Other link](/home/user/local/path/example)
              
              ### Notes
              Use SetTestTag for structured metadata; use Description for narrative context.
              Keep formatting simple and consistent.
              
              #### More heading levels
              This is a level-4 heading (####).
              #### Escapes for literals
              Use backslash escapes to show markup characters literally:
              - \\* shows a literal asterisk: \\*not italic\\*
              - \\# shows a literal hash: \\#not a heading
              - \\` shows a literal backtick: \\`not code\\`
  • It's not a good data structure design, when two dictionaries are structurally identical, but contain different values. Such a data structure is error prone if a key is missing in the other dictionary.
    The preferred solution looks like this:

    1. Outer dictionary format
      a)
      Tags:
        "tag name 1":
          Value: 256
          Visibility:
            Summary: true
        "tag name 2":
          Value: "some string"
          Visibility:
            Summary: false
      b) Alternatively using in-line style:
      Tags:
        "tag name 1": {Value: 256, Visibility: {Summary: true}}
        "tag name 2": {Value: "some string", Visibility: {Summary: false}}
    2. Outer list format
      a)
      Tags:
        - Name: "tag name 1"
          Value: 256
          Visibility:
            Summary: true
        - Name: "tag name 2"
          Value: "some string"
          Visibility:
            Summary: false
      b) Alternatively using in-line style:
      Tags:
        - {Name: "tag name 1", Value: 256, Visibility: {Summary: true}}
        - {Name: "tag name 2", Value: "some string", Visibility: {Summary: false}}
      

    Option i uses a dictionary, where each key is the name of the tag. To allow any string as tagname, the tag name is enclosed in double-quotes. Alternatively, it could be limited to identifier-like strings without double-quotes.
    A nested dictionary takes care of the value and the visibility settings. This prepares the data structure if visibility should be controlled for multiple locations.

    As YAML is interpret by the reading tool/script, we could also document that a non-existing visibility control equals to all settings to true.
    Example for equal interpretation:
    "tag name 1": {Value: "some string", Visibility: {Summary: true}}
    "tag name 1": {Value: "some string", Visibility: true}
    "tag name 1": {Value: "some string"}

    Option ii uses an outer list and moves the tag name into the inner dictionary as "Name" field.

    I personally prefer option 1b).

    Preserving the VHDL datatype is possible by writing it into YAML like so:
    "tag name 1": {Value: 256, Type: "integer", Visibility: {Summary: true}}

I'll have a look if we can modify the HTML tables with a little bit of embedded JS to support sorting/filtering.

@JimLewis

Copy link
Copy Markdown
Member

I like what I see. There is alot here. I have family visiting until Monday. I will try to do a bigger review after that.

Test tags sound like a good addition. I have been playing with deferred constants as test settings and test tags would give a way to reveal them in the reports.

Build Summary report
In the build summary report, using columns for generics and tags seems to imply that all test cases in a test suite will have these. Is this an expectation? I don't not think this conflicts with OSVVM usage.

Similar to generics, deferred constants are a good way to control settings in multiple different test cases.
With either generics or deferred constants, I see the use model as running n test cases for each of the generic
or deferred constant settings. With generics, OSVVM automatically incorporates the generic values into the
test output names - this allows a single test suite to contain all of the test outputs. For deferred constants,
OSVVM does not currently have a way to differentiate test results for different test tags (unless you have
already added this).

As a result, either different test suites need to be used for different settings or test tags would need to
be incorporated into the results file names (like is done with generics to prevent overwriting file names).
I think we need a way to incorporate the test tags into a file name. Thoughs?

In Unit Testing (the low level stuff that is done for the OSVVM library), a test suite is the set of test cases for the package.
I currently do not have any examples of where I use test tags or generics for unit testing. Thoughts @Paebbels @gmartina?

For core/chip level testing, each testbench has a test harness and many test cases that use that test harness.
There is one test suite for each unique test harness. Configuring the tests is done with either generics or
deferred constants.

@JimLewis

Copy link
Copy Markdown
Member

@gmartina @Paebbels
WRT SetTestDescription, I am more concerned about a sensible VHDL side and am not too concerned about the YAML.
I think LF in VHDL should translate to an actual LF in the file. How does it get into the string as "\n"?
Why not just put the "\n" in the original SetTestDescription call?

@Paebbels
WRT SetTestDescription, in your suggestion for multi-line in the file, how do you prevent the '-' at the beginning of a line from being understood as YAML? The TCL YAML reader reads the whole file in one read operation. If it thinks it is YAML there is largely nothing that can be done - other than writing our own YAML reader - which I think would be a mistake.

WRT @Paebbels suggestion for the tags data structure, I agree. I also like:

"tag name 1": {Value: "some string", Visibility: true}
"tag name 1": {Value: "some string"}

I don't like adding to many levels unless they are doing something useful:

"tag name 1": {Value: "some string", Visibility: {Summary: true}}

@Paebbels

Copy link
Copy Markdown
Member

I currently do not have any examples of where I use test tags or generics for unit testing.

@gmartina provided testcases for PoC's fifo_cc_got:

Dorney OSVVM Summary
image image

As I understood @gmartina, this was one of the driving forces behind the naming and tagging idea, so parameterized tests can be organized in a better way.

WRT SetTestDescription, in your suggestion for multi-line in the file, how do you prevent the '-' at the beginning of a line from being understood as YAML?

The YAML syntax is very clear about that by using the | marker and indentation.
| means, preserve linebreaks in a multi-line string (literal block scalar).
> means, concatenate all lines using a space character (literal folded scalar).
See also: https://en.wikipedia.org/wiki/YAML#Basic_components

Nested list:

key:
  - item 1
  - item 2

Text block with markdown:

key: |
  - bullet point 1
  - bullet point 2

Command line arguments on multiple lines:

ghdl: >
  -a
  --std=08
  -fexplicit

If it's easier for processing in VHDL (instead of replacing LF by indented lines), could SetTestDescription maybe take an array of lines?

SetTestDescription((
  to_line("xnxa asxsanx asknxkanx"),
  to_line("# some more text")
));

Then no splitting and replacing is required in VHDL, just iterating the array of lines (string pointers) and adding an indentation in front of them.

WRT @Paebbels suggestion for the tags data structure, I agree. I also like:

"tag name 1": {Value: "some string", Visibility: true}
"tag name 1": {Value: "some string"}

I don't like adding to many levels unless they are doing something useful:

OK.

@gmartina

Copy link
Copy Markdown
Author

In the build summary report, using columns for generics and tags seems to imply that all test cases in a test suite will have these. Is this an expectation? I don't not think this conflicts with OSVVM usage.

You can choose what to show in the Test Suite report:

# Test Case Summary: hide all generics in the summary report
HideTestCaseSummaryGenerics

# Just show G_WIDTH
SetTestCaseSummaryGenerics G_WIDTH

# Show all (default)

Same table format when showing Generics and Tags is disabled and there is no Brief:
image

In Unit Testing (the low level stuff that is done for the OSVVM library), a test suite is the set of test cases for the package.
I currently do not have any examples of where I use test tags or generics for unit testing. Thoughts @Paebbels @gmartina?

PoC's fifo_cc_got is a good example for the Generics. You can have different tests with all combinations of Generics.
The current version of OSVVM prints them like: (TRUE, FALSE, 32, 256)
Which it is not as intuitive as seeing all combinations in columns.

Tags can be used to organize and report complex tests without using generics. It can be added in the Test Controller stimuli process.

I find this very useful for very complex designs with a lot of inputs, corner cases, combinations of scenarios...

Otherwise, the current solution would be having test file names like:
my_design_config1_scenario2_cornercase3_config4....

@gmartina

Copy link
Copy Markdown
Author

Your code example uses SetTestDescription, but it's not in the description text. I assume you also added VHDL procedures for descriptions too, right?

Do you mean in the HTML?. The description is shown in the HTML, but in one screenshot, the description section is collapsed.

@Paebbels

Copy link
Copy Markdown
Member

Do you mean in the HTML?. The description is shown in the HTML, but in one screenshot, the description section is collapsed.

Never mind. I was referring to the pull request description :).

I started reading/reviewing the actual code and found that not "all" high level additions are mentioned. I'm now step by step into that huge contribution.

@gmartina

Copy link
Copy Markdown
Author

Summary of updated PR with your suggestions

  • changed name SetTestTag to AddTestTag. Using functions from TextUtilPkg and added IsReal. Changed Tags array to a linked list.

  • Changed tag type approach. Adding TagValueType enumeration and updated AddTestTag procedures to handle various data types (string, boolean, integer, real, time, std_logic).

  • Description written as a multi-line string without embedded escape sequences for linebreaks.

Problem: We need \ for titles (#)

        Brief: "This is a short summary of TestDescription_Demo1"
        Description: |
          This demo shows how to document a test case using a *formatted* description.
          The goal is to keep it readable in both YAML and HTML.
          
          \## What this test does
          - Exercises a simple pass case
          - Demonstrates **bold** and *italic* emphasis
          - Demonstrates bullet lists
          - Demonstrates inline code like `AddTestTag("Name", Value)`
          - Demonstrates links like [OSVVM docs](https://osvvm.github.io)
          - Demonstrates links like [Other link](/home/user/local/path/example)
  • Outer dictionary format using in-line style.
        Tags:
          "Cfg": {Value: "CFG_2", Type: "TAG_STRING", Visibility: {Summary: false}}
          "Scenario": {Value: "Maximum Burst", Type: "TAG_STRING", Visibility: {Summary: false}}
          "Priority": {Value: "Medium", Type: "TAG_STRING", Visibility: {Summary: false}}
          "Condition": {Value: "Back-pressure Active", Type: "TAG_STRING", Visibility: {Summary: false}}
          "datawidth": {Value: 8, Type: "TAG_INT", Visibility: {Summary: false}}
          "burstlength": {Value: 256, Type: "TAG_INT", Visibility: {Summary: true}}
          "syncregs": {Value: true, Type: "TAG_BOOL", Visibility: {Summary: true}}
          "bufferenable": {Value: false, Type: "TAG_BOOL", Visibility: {Summary: true}}
          "delay_time": {Value: "100 ns", Type: "TAG_TIME", Visibility: {Summary: true}}
          "cfg_real": {Value: 3.14, Type: "TAG_REAL", Visibility: {Summary: true}}
  • Append one line to the test description. Automatically inserts LF between lines. Added alias for shorter name.
procedure SetTestDescription(Description : string ) ;
 -- Append one line to the test description. Automatically inserts LF between lines.
 -- This allows writing readable multi-line descriptions without "& LF &" concatenation.
 procedure AppendTestDescriptionLine(Line : string ) ;
 -- Short alias for AppendTestDescriptionLine.
 alias DescLn is AppendTestDescriptionLine [string] ;

Now we don't need LF:

    ClearTestDescription ;
    DescLn("This demo shows how to document a test case using a *formatted* description.") ;
    DescLn("The goal is to keep it readable in both YAML and HTML.") ;
    DescLn("") ;
    DescLn("## What this test does") ;
    DescLn("- Exercises a simple pass case") ;

Other suggestions:

If it's easier for processing in VHDL (instead of replacing LF by indented lines), could SetTestDescription maybe take an array of lines?

SetTestDescription((
  to_line("xnxa asxsanx asknxkanx"),
  to_line("# some more text")
));

I tried to implement this but had some type problems. Maybe I revisit this approach in the future.

@Paebbels

Paebbels commented Dec 28, 2025

Copy link
Copy Markdown
Member

I tried to implement this but had some type problems. Maybe I revisit this approach in the future.

What problems did you have? Maybe I can help.

type line_vector is array(natural range <>) of line;
type line_vectorP is access line_vector;

procedure SetTestDescription(lines : line_vector);
procedure SetTestDescription(lines : line_vector) is
begin
  description = new line_vector'(lines);
end procedure;

function to_line(value : string) return line;
function to_line(value : string) return line is
begin
  return new string'(value);
end function;

I did not test, just wrote down my idea.

@JimLewis

Copy link
Copy Markdown
Member

@Paebbels
From a use model perspective, I like:

    SetTestDescription(
      "This demo shows how to document a test case using a *formatted* description." & LF &
      "The goal is to keep it readable in both YAML and HTML." & LF & LF &
      "## What this test does" & LF &
      "- Exercises a simple pass case" & LF &
      "- Demonstrates **bold** and *italic* emphasis" & LF &
      "- Demonstrates bullet lists" & LF &
      "- Demonstrates inline code like `SetTestTag(""Name"", Value)`" & LF &
      "- Demonstrates links like [OSVVM docs](https://osvvm.github.io)" & LF &
      "- Demonstrates links like [Other link](/home/user/local/path/example)" & LF & LF &
      "### Notes" & LF &
      "Use SetTestTag for structured metadata; use Description for narrative context." & LF &
      "Keep formatting simple and consistent." & LF & LF &
      "#### More heading levels" & LF &
      "This is a level-4 heading (####)." & LF &
      "#### Escapes for literals" & LF &
      "Use backslash escapes to show markup characters literally:" & LF &
        "- \* shows a literal asterisk: \*not italic\*" & LF &
        "- \# shows a literal hash: \#not a heading" & LF &
        "- \` shows a literal backtick: \`not code\`" & LF
    ) ;

In particular, I do not think the user should have to add extra decoration:

SetTestDescription((
  to_line("xnxa asxsanx asknxkanx"),
  to_line("# some more text")
));

Although the to_line would be interesting as overloading.

Since this is going to the YAML file, why not use the YAML (or is that tcl) new line character "\n" and just include it in the string handling?

    SetTestDescription(
      "This demo shows how to document a test case using a *formatted* description.\n" &
      "The goal is to keep it readable in both YAML and HTML.\n\n" & 
      "## What this test does\n" &

I don't see the YAML file as something that humans read. So I am ok with the value being a single string in YAML. If we switched to \n as the new line, then the whole string could go into the YAML unmodified. It is not clear to me that we need to remove accidental characters from the text - is *.md going to throw an error if it sees a CR or HT in the file?

@JimLewis

Copy link
Copy Markdown
Member

Late yesterday I had the realization that this sort of information is separate from the AlertLogPkg. I think the reason it was put there is because SetTestName is there. SetTestName is in AlertLogPkg because the TestName is the name of the top level AlertLog bin, so it had to be there.

I realize that the proposal includes an update to SetTestName with an addition of the optional SetTestTitle. That can be managed a number of ways:
- SetTestName is overloaded in the new package with the extra parameter (rather than it being a default) and
it calls AlertLogPkg.SetTestName to set the test name. And the new package is compiled after AlertLogPkg
- SetTestName is updated as proposed and calls SetTestTitle - implying the new package is compiled before AlertLogPkg

@gmartina Do you want to propose a package name? OSVVM uses a Pkg suffix in the name. This would also simplify organizing the unit tests for the package.

@JimLewis

JimLewis commented Dec 30, 2025

Copy link
Copy Markdown
Member

@gmartina Is it the printing of the YAML file that had you add this to AlertLogPkg? If the new package is analyzed before AlertLogPkg, AlertLogPkg could call it when it is doing its printing or EndOfTestReports could call the printing from the new package just after calling the printing for the AlertLogPkg.

I think I like calling it from EndOfTestReports best - this is in ReportPkg.vhd.

@JimLewis

JimLewis commented Dec 30, 2025

Copy link
Copy Markdown
Member

The advantage of decoupling the VHDL API from AlertLogPkg and having EndOfTestReports call the printing for the VHDL API separately is that we can pull the package with little to no risk to AlertLog capability.

Likewise when updating the package we do not have to consider any side-effects on AlertLogPkg.

Outside of OSVVM internals, when one references the OSVVM library they use the context clause:

library OSVVM ; 
context OSVVM.OsvvmContext ; 

So to deploy the new package, OSVVM simply includes it in the context.

@Paebbels

Copy link
Copy Markdown
Member

@JimLewis @gmartina I think a new package sounds reasonable. I also came to the conclusion, that OSVVM has no central "configuration settings" data structure for the top-level name (also used by AlertLog), the title, description, tags, etc. AlertLog is a big piece, but its one island besides coverage, random, scoreboards, etc. So maybe that PR is a good starting point for introducing a new central part of OSVVM holding these information. As Jim mentioned, the SetTestName(..., ....) as an overload from that package sounds very good.

The question is, these modifications go beyond a normal contribution via PR. I suggest to merge it into a tag-feature branch and further modifications are on @JimLewis. He can then create a PR to dev, were we three can review again after he did some restructuring. @gmartina can then give feedback if his original proposal and usecases are covered.

@gmartina if other contributions are changes come to your mind with respect to this feature set, you could still propose PR from your (new?) branch to tag-feature.

@Paebbels

Copy link
Copy Markdown
Member

Using the following code is preferred:

SetTestDescription(
  "This demo shows how to document a test case using a *formatted* description." & LF &
  "The goal is to keep it readable in both YAML and HTML." & LF &
  LF &
  "## What this test does" & LF
);

The 2nd proposal was just an idea, to maybe simplify string handling.

You cannot emit LF into YAML, because this will create invalid YAML files! Emitting a multi-line string as a literal block is the correct way of handling strings in YAML. Everything else is botchery.

Either any VHDL string can be converted to a YAML string using correct escaping, or an error must be raised by OSVVM, otherwise a software is forcefully hiding a bug, which is not an acceptable software architecture for me.

A string can be split at LF into multiple lines. These can be stored either as an array of lines or as a linked list (OSVVM has a package for that data structure). Such a replacement algorithm is not so complicated.

While YAML is an intermediate machine-readable format, it's also a human-readable format. For debugging and other investigative processes, we should keep such a file as human-readable as possible. Especially, as it's quite simple to create the required output format. Why should we deliberately create something not human-readable?


We could also think about writing a YAML package / protected type, which is handling the file format.

@weilanad

Copy link
Copy Markdown

This change would be quite helpful. I am currently working on a testbench where I have to vary multiple generics, such as (Pseudocode)

CLOCK_DIVIDER     = 2, 4, 8
CLOCK_FREQUENCY   = "100 MHz", "150 MHz", "200 MHz"
DURATION          = 1 ... 14
ENABLE_FIX_LENGTH = True, False

This alone results in 252 possible combinations and a structured overview with the possibility to filter would help a lot.

Comment thread OsvvmScriptsCore.tcl
# ClearTestSuiteDescription
# Clears any previously set suite-level description.
proc ClearTestSuiteDescription {} {
set ::osvvm::TestSuiteDescription ""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize TestSuiteDescription in OsvvmSettingsRequired.tcl

Comment thread OsvvmScriptsCore.tcl
Comment on lines +1441 to +1448
# GetTestSuiteDescription
# Returns the currently configured suite-level description.
proc GetTestSuiteDescription {} {
if {[info exists ::osvvm::TestSuiteDescription]} {
return $::osvvm::TestSuiteDescription
}
return ""
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is initialized in OsvvmSettingsRequired.tcl, then this simplifies to:

Suggested change
# GetTestSuiteDescription
# Returns the currently configured suite-level description.
proc GetTestSuiteDescription {} {
if {[info exists ::osvvm::TestSuiteDescription]} {
return $::osvvm::TestSuiteDescription
}
return ""
}
# GetTestSuiteDescription
# Returns the currently configured suite-level description.
proc GetTestSuiteDescription {} {
return $::osvvm::TestSuiteDescription
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am new to these modification things. I note that the above modification requires another action as well.

Comment thread OsvvmScriptsCore.tcl
Comment on lines +1456 to +1461
if {![info exists ::osvvm::TestSuiteBriefMaxLength]} {
set ::osvvm::TestSuiteBriefMaxLength 120
}
if {$::osvvm::TestSuiteBriefMaxLength > 0 && [string length $Brief] > $::osvvm::TestSuiteBriefMaxLength} {
puts "Warning: SetTestSuiteBrief length ([string length $Brief]) exceeds TestSuiteBriefMaxLength ($::osvvm::TestSuiteBriefMaxLength)"
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any limits should be applied to the VHDL code so the user gets the information earlier.

Comment thread OsvvmScriptsCore.tcl
Comment on lines +1472 to +1477
if {![info exists ::osvvm::TestSuiteTitleMaxLength]} {
set ::osvvm::TestSuiteTitleMaxLength 80
}
if {$::osvvm::TestSuiteTitleMaxLength > 0 && [string length $Title] > $::osvvm::TestSuiteTitleMaxLength} {
puts "Warning: SetTestSuiteTitle length ([string length $Title]) exceeds TestSuiteTitleMaxLength ($::osvvm::TestSuiteTitleMaxLength)"
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any limits should be applied to the VHDL code so the user gets the information earlier.

Comment thread OsvvmScriptsCore.tcl
Comment on lines +1492 to +1495
if {[info exists ::osvvm::TestSuiteTitle]} {
return $::osvvm::TestSuiteTitle
}
return ""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize TestSuiteTitle to "" in OsvvmSettingsRequired.tcl. Then simply return the value. Make sure it is set back to "" when the Build finishes or a new TestSuite is introduced.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other places in OSVVM Tcl scripts that use info exists on variables - Iooking back I think that was a mistake and it should be initialized.

Comment thread OsvvmSettingsRequired.tcl
Comment on lines +69 to +79
# -------------------------------------------------
# Brief length guard (soft warning)
# 0 disables warning.
variable TestSuiteBriefMaxLength 120

# -------------------------------------------------
# Test Case Summary (HTML) column limits
# These caps prevent the summary table from becoming too wide when many generics/tags exist.
# 0 (or negative) disables the cap.
variable TestCaseSummaryMaxGenericsColumns 12
variable TestCaseSummaryMaxTagsColumns 12

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set these in OsvvmSettingsDefaults.tcl. Doing so allows OsvvmSettingsLocal.tcl to override them with user settings.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OTOH, do we care about checking things like this. Yes it potentially mangles the output. Why do I care - the user looks at it, realizes their mistake and updates their code. A similar issue will occur if they choose to use tag names that are silly long in length.

If we suppress some items, they will wonder why it did not print - and potentially add additional ones to try to understand the issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, it is not clear to me how the Test Case summary can accommodate any test tags or generic values. The problem is that each test case can have a different number of generics / tags. So the report generator is going to have to read all of the tests in that test suite, calculate the maximum number and whether a test case uses them or not, there will be space in the report for them.

We also have the test brief, which could include this sort of information in the build reports.

Comment on lines +110 to +120
set Escaped [string map [list "\\" "\\\\" "\"" "\\\"" "\n" "\\n" "\r" "\\r" "\t" "\\t"] $Value]
return "\"$Escaped\""
}


# -------------------------------------------------
# FormatYamlDoubleQuotedScalar
# Always returns a double-quoted YAML string (never native/null).
proc FormatYamlDoubleQuotedScalar {Value} {
set Value [SanitizeTextForReport $Value]
set Escaped [string map [list "\\" "\\\\" "\"" "\\\"" "\n" "\\n" "\r" "\\r" "\t" "\\t"] $Value]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this there so that the embedded markdown text preserves the control characters?

puts $YamlFile "${Prefix}${DictName}:"
foreach {Name Value} $DictValues {
puts $YamlFile "${Prefix} ${Name}: \"$Value\""
foreach Name [lsort -dictionary [dict keys $DictValues]] {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to sort the dictionary or do we want to present parameters in the order they were entered?

This will change backward compatibility with OSVVM's current reports which present parameters in the order they were presented. Probably not a problem since currently OSVVM does not self-check this sort of information. I don't know if anyone else cares or not.

Comment on lines +61 to +64
regsub -all {[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]} $Text { } Clean
return $Clean
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we worried about these? The text we have comes from VHDL and in VHDL it is hard to get non-printing characters - it has to be deliberate.

Comment thread ReportAlert2Html.tcl
Comment on lines +73 to +77
set CandidateTitle [string trim [dict get $Alert2HtmlDict Title]]
if {$CandidateTitle ne ""} {
set DisplayName $CandidateTitle
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you are using "string trim" with the title. Are we expecting leading or training white space that needs to be removed?

SetTestTitle(" ABC ");

@JimLewis

Copy link
Copy Markdown
Member

The comments that were just posted, I had started quite some time ago.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants