Skip to content

Conversation

@gmartina
Copy link

@gmartina gmartina commented Dec 26, 2025

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
Copy link
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
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
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
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
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
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
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
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
Copy link
Member

Paebbels commented Dec 28, 2025

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
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
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
Copy link
Member

JimLewis commented Dec 30, 2025

@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
Copy link
Member

JimLewis commented Dec 30, 2025

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
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
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.

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.

3 participants