Skip to content

Greatly simplify test-suite driver programs - #86

Closed
rouson wants to merge 34 commits into
mainfrom
test-harness-feature
Closed

Greatly simplify test-suite driver programs#86
rouson wants to merge 34 commits into
mainfrom
test-harness-feature

Conversation

@rouson

@rouson rouson commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

This PR

  • Simplifies the test-suite driver program, test/main.f90, to a form that will facilitate automating the driver creation.
  • Refactors command_line_test_m using idioms based on a new .expect. unary operator.
  • Adds .expect. to the table of idioms in the README.md.
  • Refactors the demo/ subdirectory to demonstrate the new driver structure.
  • Support older GCC compiler versions by
    a. Conditionally gutting the new driver when the preprocessor detects GCC versions below 14.3.0 and
    b. Retaining the old driver in test/legacy-main.F90 but conditionally gutting it with GCC 14.3.0 or later versions.

New Features

  1. A unary operator(.expect.) that maps a logical expression to a test_diagnosis_t object.
  2. A test-harness abstraction representing a polymorphic array of tests via
    a. A test_harness_t derived type with a test_fixture_t allocatable array component.
    b. A test_fixture_t derived type with a polymorphic test_t component.

Driver simplifications

  1. Move the final test results tallying and printing into test_harness_t's type-bound report_results subroutine.
  2. Move the help/usage output into the report_results subroutine.
  3. The new driver consists of only the following elements:
    a. Use statements and declarations,
    b. One array constructor containing structure constructors and user-defined structure constructor invocations,
    c. A single call to report_results on the test harness.

rouson added 7 commits August 9, 2025 07:16
This commit introduces the test_harness_t and test_fixture_t
derived types and uses them to refactor and simplify the test-suite
driver program: test/main.F90.
This commit reduces the amount of code that end users must write
by moving the reporting of the final tally of test passes, test
count, and skipped tests to the test_harness_t's "report"
type-bound procedure.
This commit the code that checks whether the test suite is running
in GitHub CI and checks whether the user requested to run the
command_line_t tests.  The code is moved from the test-suite driver
to the actual test, which further simplifies the test-suite main
program.
@rouson
rouson requested a review from ktras August 9, 2025 15:57
@rouson
rouson force-pushed the test-harness-feature branch from 56e126f to 7ed8437 Compare August 10, 2025 18:36
@rouson
rouson force-pushed the test-harness-feature branch from bfa2155 to 06ca107 Compare August 11, 2025 02:37

@bonachea bonachea left a comment

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.

Looks like a nice improvemen!

I made a few suggestions based on a quick skim.

Comment thread demo/test/main.f90
Comment on lines +20 to +40
subroutine stop_if_compiler_too_old
character(len=:), allocatable :: compiler_identity
integer major, minor
compiler_identity = compiler_version()
if (index(compiler_identity, "GCC")==1) then
associate( final_dot => index(compiler_identity ,"." ,back=.true.))
associate( penultimate_dot => index(compiler_identity(:final_dot-1) ,"." ,back=.true.))
associate(space_before_version => index(compiler_identity(:penultimate_dot-1) ," " ,back=.true.))
associate( &
major_string => compiler_identity(space_before_version+1 : penultimate_dot-1) &
,minor_string => compiler_identity( penultimate_dot+1 : final_dot-1) &
)
read(major_string, '(i2)') major
read(minor_string, '(i1)') minor
if ((major < 14) .or. (major==14 .and. minor<3)) stop "'"// compiler_identity //"' too old: GCC >= 14.3.0 required"
end associate
end associate
end associate
end associate
end if
end subroutine

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.

This can be written far more concisely using the preprocessor.

You will also need to rename the file back to .F90.

Suggested change
subroutine stop_if_compiler_too_old
character(len=:), allocatable :: compiler_identity
integer major, minor
compiler_identity = compiler_version()
if (index(compiler_identity, "GCC")==1) then
associate( final_dot => index(compiler_identity ,"." ,back=.true.))
associate( penultimate_dot => index(compiler_identity(:final_dot-1) ,"." ,back=.true.))
associate(space_before_version => index(compiler_identity(:penultimate_dot-1) ," " ,back=.true.))
associate( &
major_string => compiler_identity(space_before_version+1 : penultimate_dot-1) &
,minor_string => compiler_identity( penultimate_dot+1 : final_dot-1) &
)
read(major_string, '(i2)') major
read(minor_string, '(i1)') minor
if ((major < 14) .or. (major==14 .and. minor<3)) stop "'"// compiler_identity //"' too old: GCC >= 14.3.0 required"
end associate
end associate
end associate
end associate
end if
end subroutine
#if __GNUC__ && ( __GNUC__ < 14 || (__GNUC__ == 14 && __GNUC_MINOR__ < 3) )
stop "GFortran " // __VERSION__ // " too old: GCC >= 14.3.0 required"
#endif

Comment thread test/legacy-main.F90
program main
!! Julienne unit tests driver

#if defined(__GCC__) && (GCC_VERSION < 140300)

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 believe it's actually __GNUC__ not __GCC__

Suggested change
#if defined(__GCC__) && (GCC_VERSION < 140300)
#if defined(__GNUC__) && (GCC_VERSION < 140300)

Comment thread test/main.F90

program main
!! Julienne unit tests driver
#if ! defined(__GCC__) || (GCC_VERSION >= 140300)

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.

Suggested change
#if ! defined(__GCC__) || (GCC_VERSION >= 140300)
#if ! defined(__GNUC__) || (GCC_VERSION >= 140300)

Comment on lines +7 to +11
#ifdef __GNUC__
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
#define GCC_VERSION 0
#endif

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.

Minor nitpick:

For the "not Gfortran" case, you might instead consider leaving GCC_VERSION undefined:

Suggested change
#ifdef __GNUC__
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
#define GCC_VERSION 0
#endif
#ifdef __GNUC__
# define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
# undef GCC_VERSION
#endif

Then later your tests become more readable and slightly less error-prone:

#if ! defined(GCC_VERSION) || (GCC_VERSION >= 140300)

Comment thread test/modules/assert_test_m.F90
@rouson

rouson commented Aug 13, 2025

Copy link
Copy Markdown
Contributor Author

This PR is superseded by PR #91.

@rouson rouson closed this Aug 13, 2025
@rouson
rouson deleted the test-harness-feature branch August 23, 2025 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move --contains test filtering logic into Julienne

2 participants