fortesg / fortrantestgenerator

Unit test generator for Fortran applications using Capture & Replay
GNU General Public License v3.0
24 stars 5 forks source link

Documentation request: a "Hello, world!" unit test example #16

Open rouson opened 6 years ago

rouson commented 6 years ago

I'm excited about the prospects of applying fortrantestgenerator on two projects and finally diving in after some initial intimidation. It would be really helpful for the documentation to include the generation of a unit test for a "Hello, world!" program in a new GETTING_STARTED.md file for a target audience that is unfamiliar with python.

I used pip to install cheetah3, downloaded the other prerequisites to the same directory as fortrantestgenerator, and built serialbox2 using cmake:

$ ls -l
total 12
drwxrwxr-x  4 rouson rouson 4096 Jun 28 16:43 fortrancallgraph
drwxrwxr-x  5 rouson rouson 4096 Jun 28 16:52 fortrantestgenerator
drwxrwxr-x 10 rouson rouson 4096 Jun 28 15:45 serialbox2-2.4.0

Now I am struggling to generate a unit test for the following "Hello, world!" program:

$ cat hello.f90
module messages
  implicit none

  private
  public :: save_message, recorded_message

  character(len=:), allocatable, save :: recording

contains

  subroutine save_message(message)
     character(len=*), intent(in) ::  message
     recording = message
  end subroutine

  function recorded_message() result(string)
    character(len=:), allocatable :: string
    if (.not. allocated(recording)) allocate(character::string)
    string = recording
  end function

end module

program main
  use messages, only : save_message, recorded_message
  implicit none
  call save_message("Hello, world!")
  print *,recorded_message()
end program

At Step 8. Create capture code in the fortrantestgenerator README.md, I substituted the Fortran module name messages for my_module and the subroutine name save_message for my_subroutine. I get the following error:

$ gfortran -save-temps -g -o hello hello.f90
$ ./FortranTestGenerator.py -c hello_word save_message
Missing config variable: TEST_SOURCE_DIR 

so then I edited the TEST_SOURCE_DIR definition in config_fortrantestgenerator.py to read

TEST_SOURCE_DIR = ftgDir + '../test_drivers'

It would be great if a working default value were included in the version of config_fortrantestgenerator.py in the repository. Barreling forwarded with the above edit yields

$ ./FortranTestGenerator.py -c hello_word save_message
Missing config variable: SOURCE_DIRS
Missing config variable: ASSEMBLER_DIRS

but neither SOURCE_DIRS nor ASSEMBLER_DIRS is defined in config_fortrantestgenerator.py and neither is mentioned in the README.md so now I'm doing recursive grep on these variable names and pondering how much further to venture down the rabbit hole without a flashlight. Thanks for any help you can provide.

rouson commented 6 years ago

I just fixed a typo in my TEST_SOURCE_DIR definition so that it now reads

TEST_SOURCE_DIR = ftgDir + '/../test_drivers'

and a colleague pointed out the configure_fortrancallgraph.py file, where I have set

fcgDir = os.path.dirname(os.path.realpath(__file__))
ASSEMBLER_DIRS = fcgDir + '/../project'
SOURCE_DIRS = fcgDir + '/../project'

I then moved hello.f90 to the above project directory and get the following:

$ mkdir ../project
$ mv hello.f90 ../project
$ cd ../project
$ gfortran -save-temps -g -o hello hello.f90
$ cd ../fortrantestgenerator
$ ./FortranTestGenerator.py -c messages save_message
usage: FortranTestGenerator.py [-h] [-b] [-c] [-r] [-cf CONFIGFILE]
                               [module] [subroutine]
FortranTestGenerator.py: error: Subroutine __messages_MOD_save_messages not found!

In case it helps, I'm using gfortran 8.1.0 built from source after applying a very small patch to the compiler to fix a bug. I wonder what versions of gfortran you've tested and I wonder if the name mangling scheme has changed -- seems unlikely but there's a remote chance the name mangling might have been adjusted when gfortran added support for Fortran 2008 submodules sometime around version 6 or 7.

rouson commented 6 years ago

FYI, I then deleted an erroneous s in the invocation of fortrantestgenerator and verified that the object file contains the mangled subroutine name that fortrantestgenerator reports as missing:

$ nm hello.o
0000000000000008 B _F.messages_MOD_recording
                 U free
                 U _gfortran_os_error
                 U _gfortran_runtime_error_at
                 U _gfortran_set_args
                 U _gfortran_set_options
                 U _gfortran_st_write
                 U _gfortran_st_write_done
                 U _gfortran_transfer_character_write
000000000000035c T main
000000000000028c t MAIN__
                 U malloc
                 U memmove
                 U memset
0000000000000000 T __messages_MOD_recorded_message
0000000000000000 B __messages_MOD_recording
0000000000000189 T __messages_MOD_save_message
00000000000000a0 r options.3.3801
                 U realloc
0000000000000010 b slen.1.3794
$ cd ../fortrantestgenerator/
$ ./FortranTestGenerator.py -c messages save_message
usage: FortranTestGenerator.py [-h] [-b] [-c] [-r] [-cf CONFIGFILE]
                               [module] [subroutine]
FortranTestGenerator.py: error: Subroutine __messages_MOD_save_message not found!
chovyy commented 6 years ago

Thanks a lot for your request, @rouson. You are right, such a tutorial would be nice, but I cannot promise that I will be able to realize it soon.

Regarding your own efforts: FortranCallGraph assumes that every module is located in a file with the same name unless not specified otherwise, so you have to put messages into a file called messages.f90 or add the following to your config_fortrancallgraph.py:

SPECIAL_MODULE_FILES = {'messages': 'hello.f90'}