Ada: omit newline when redirecting to stdout (testing Put)

827 views Asked by At

I am trying to write a test for a method with a simple Ada.Text_IO.Put. For the sake of simplicity, this is a made up method that I want to test:

procedure Say_Something is
begin
   Put("Something.");
end Say_Something;

In my AUnit test, I have:

procedure Test_Put (T : in out Test) is
   pragma Unreferenced (T);
   use Ada.Text_IO;

   Stdout : constant File_Type := Standard_Output;
   Put_File_Name : constant String := "say_something_test.txt";
   Put_File : File_Type;

   Expected : constant String := "Something.";
begin
   --  Create the output file and redirect output
   Create (Put_File, Append_File, Put_File_Name);
   Set_Output (Put_File);

   Say_Something;

   --  Redirect output to stdout and close the file
   Set_Output (Stdout);
   Close (Put_File);

   --  Read file
   declare
      File_Size : constant Natural :=
         Natural (Ada.Directories.Size (Put_File_Name));
         Actual : String (1 .. File_Size);
   begin
      Actual := Read_File (Put_File_Name, File_Size);
      Ada.Directories.Delete_File (Put_File_Name);

      Assert (Expected = Actual,
              "Expected " & '"' & Expected & '"' & ", " &
              "Got "      & '"' & Actual   & '"');
   end;
end Test_Put;

function Read_File (File_Name : String; File_Size : Natural)
   return String is
   subtype File_String is String (1 .. File_Size);
   package File_String_IO is new Ada.Direct_IO (File_String);

   File : File_String_IO.File_Type;
   Contents : File_String;
begin
   File_String_IO.Open (File, File_String_IO.In_File, File_Name);
   File_String_IO.Read (File, Contents);
   File_String_IO.Close (File);

   return Contents;
end Read_File;

Unfortunately, the result is:

FAIL Test Vectors.Put
    Expected "Something.", Got "Something.
"

It seems that Ada automagically adds a newline to the end of the file. I realize that I could add a (CR)LF to my expected string like this:

Expected : constant String := "Something.";
   & Ada.Characters.Latin_1.CR
   & Ada.Characters.Latin_1.LF;

but a) It does not feel right to alter my expected string and b) This will run on a Windows machine, but on Unix/Linux/Mac I would have to drop the "CR". In other words, the success of my test run is platform dependent while my code is not, which is bad.

So my question is: how can I write to the file without appending a newline? Other suggestions on how to test for output are highly welcome as well.

I have seen this related question but couldn't deduce any useful information from it apart that I might try the Append_File instead of the Out_File mode, which did not resolve my issue.

2

There are 2 answers

0
ajb On BEST ANSWER

Sorry for my previous answer, I missed that the file you were reading was one you created earlier in the program.

In Ada.Text_IO, the RM (A.10(7-8)) says "the end of a file is marked by the combination of a line terminator immediately followed by a page terminator and then a file terminator", and "The actual nature of terminators is not defined by the language and hence depends on the implementation" ... "they are not necessarily implemented as characters or as sequences of characters". So when you create say_something_test.txt, it will always end with a "line terminator" although that doesn't necessarily mean it will end with an LF. That's implementation-dependent. The only thing you're guaranteed is that if you use Ada.Text_IO to create a file, it will work correctly if you read it back in with Ada.Text_IO. But if you want this level of control of the actual bytes written to the file, then Ada.Text_IO would not really be suitable; you'd be better off using Ada.Stream_IO.

Whether an CR and/or LF is written to the end of the file is implementation-dependent. It looks like GNAT does add LF (and maybe CR) to the end, and it doesn't provide a way (such as a Form parameter) to turn this behavior off. At least I didn't see one in the manual.

If you're really determined to use Ada.Text_IO to write say_something_test.txt and Ada.Direct_IO to read it back in, then you need to be aware that the file may or may not contain CR/LF, and the input routine should check for those characters and strip them off so that the string can be compared to the expected value.

0
egilhh On

You're using Text_IO for the output, but Direct_IO when reading it back in. You shouldn't mix them like that since they do different things. In your simple example, all output is test, so I recommend you use Text_IO to read it back in in your test as well.