------------------------------------------------------------------------------
-- XML/Ada - An XML suite for Ada95 --
-- --
-- Copyright (C) 2001-2017, AdaCore --
-- --
-- This library is free software; you can redistribute it and/or modify it --
-- under terms of the GNU General Public License as published by the Free --
-- Software Foundation; either version 3, or (at your option) any later --
-- version. This library is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
-- --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception, --
-- version 3.1, as published by the Free Software Foundation. --
-- --
-- You should have received a copy of the GNU General Public License and --
-- a copy of the GCC Runtime Library Exception along with this program; --
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
-- . --
-- --
------------------------------------------------------------------------------
pragma Ada_05;
with Ada.Direct_IO;
with Ada.Exceptions; use Ada.Exceptions;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO.Text_Streams; use Ada.Text_IO.Text_Streams;
with Ada.Unchecked_Deallocation;
with DOM.Core.Documents; use DOM.Core, DOM.Core.Documents;
with DOM.Core.Nodes; use DOM.Core.Nodes;
with DOM.Readers; use DOM.Readers;
with GNAT.Command_Line; use GNAT.Command_Line;
with GNAT.Expect; use GNAT.Expect;
with GNAT.OS_Lib; use GNAT.OS_Lib;
with Input_Sources.File; use Input_Sources.File;
with Input_Sources.Http; use Input_Sources.Http;
with Input_Sources; use Input_Sources;
with Sax.Encodings; use Sax.Encodings;
with Sax.Readers; use Sax.Readers;
with Sax.Symbols; use Sax.Symbols;
with Sax.Utils; use Sax.Utils;
with Testxml_Support; use Testxml_Support;
with Unicode.CES; use Unicode.CES;
with Unicode.Encodings; use Unicode.Encodings;
with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Strings.Hash;
-- Try also
-- ./testxml http://java.sun.com/j2ee/1.4/docs/tutorial/examples/jaxp
-- /dom/samples/slideSample01.xml
procedure Testxml is
Show_Invalid_Encoding : constant Boolean := False;
-- If True, an unsupported encoding reported by the XML parser is
-- considered as a fatal error for the testsuite. If False, the test is
-- simply ignored
Run_XML_1_1_Tests : Boolean := False;
-- Whether we should run XML 1.1 tests. If False, only XML 1.0 tests are
-- run
Run_Disabled_Tests : constant Boolean := False;
-- If True, tests disabled in the "disable" file are run.
Cst_Tmp_File1_Name : aliased String := "testxml_tmp1";
Tmp_File1_Name : constant GNAT.OS_Lib.String_Access :=
Cst_Tmp_File1_Name'Unchecked_Access;
Cst_Tmp_File2_Name : aliased String := "testxml_tmp2";
Tmp_File2_Name : constant GNAT.OS_Lib.String_Access :=
Cst_Tmp_File2_Name'Unchecked_Access;
-- Do not use temporary file names created by Create, since otherwise
-- valgrind will report a memory leak in the GNAT runtime (which is not
-- really a leak, just unfreed memory on exit).
package String_Hash is new Ada.Containers.Indefinite_Hashed_Maps
(Key_Type => String,
Element_Type => Boolean,
Hash => Ada.Strings.Hash,
Equivalent_Keys => "=");
use String_Hash;
Disabled : String_Hash.Map;
procedure Parse_Disabled;
-- Parse the "disable" file, and set the [Disabled] variable
procedure Unchecked_Free is new Ada.Unchecked_Deallocation
(Input_Source'Class, Input_Source_Access);
package Character_IO is new Ada.Direct_IO (Character);
Silent : Boolean := False;
-- If True, do not print the resulting DOM tree when testing a single XML
-- file.
With_URI : Boolean := False;
Dump : Boolean := False;
Name_Start : Natural;
Validate : Boolean := False;
Valid_Chars : Boolean := True;
Must_Normalize : Boolean := False;
Support_Namespaces : Boolean := True;
Encoding_Out : Unicode.Encodings.Unicode_Encoding := Get_By_Name ("utf-8");
EOL : Byte_Sequence_Access := new Byte_Sequence'(Sax.Encodings.Lf_Sequence);
Print_Comments : Boolean := False;
Print_XML_PI : Boolean := False;
Collapse_Empty_Nodes : Boolean := False;
Auto_Run : Boolean := False;
Verbose : Boolean := False;
Pretty_Print : Boolean := False;
Symbols : Symbol_Table;
type Testcase_Type is (Type_WF, -- XML OK, Validation=No
Type_Not_WF,
Type_Valid, -- XML OK, Validation=Yes
Type_Invalid,
Type_Error
);
type Result_Type is (Result_Success, -- Matches expected result
Result_Failure, -- Doesn't match expected result
Result_Ignore, -- Explicitly marked as "unsupported"
Result_XML_1_1, -- Test for XML 1.1
Result_Encoding, -- Invalid encoding
Result_IE); -- Unexpected exception
type Testcases_Results is array (Testcase_Type, Result_Type) of Natural;
type Test_Description is record
Base : Unbounded_String;
ID : Unbounded_String;
Description : Unbounded_String;
URI : Unbounded_String;
Section : Unbounded_String;
Output : Unbounded_String;
Version : Unbounded_String;
Test_Type : Testcase_Type;
Edition : XML_Versions;
Namespace : Boolean;
end record;
function Open_Input (XML_File : String) return Input_Source_Access;
-- Open a given input_source. According to the file prefix, various types
-- of sources can be open
procedure Run_Single_Test (XML_File : String; Edition : XML_Versions);
-- Parse XML_File, and print the output according to the command-line
-- parameters
procedure Run_Testsuite;
-- Parse the W3C's testsuite description file, and run every test in it.
-- Return True if all tests succeeded
procedure Run_Testcases
(N : Node; Base : String; Results : in out Testcases_Results);
-- Parse a node from tests/xmlconf.xml to drive the automatic
-- testsuite.
procedure Run_Test
(Entities : String;
Descr : Test_Description;
Results : in out Testcases_Results);
-- Run a single test from the W3C testsuite
function Get_Attribute (N : Node; Attribute : String) return String;
-- Query an attribute from N. The empty string is returned if the attribute
-- does not exists
function Diff_Output
(Reader : My_Tree_Reader'Class;
Descr : Test_Description) return String;
-- Compare the output of a test with the expected output.
function Image (Num : Integer; Width : Natural) return String;
-- Return the image of [Num], on [Width] characters.
-- This includes the leading whitespace
procedure Print_Test_Result
(Reader : My_Tree_Reader'Class;
Descr : Test_Description;
Result : Result_Type;
Msg : String;
Results : in out Testcases_Results);
-- Print the result for the test.
-- Checks the XML output of the test if needed
function Test_Prefix (Typ : Testcase_Type) return String;
-- Return a short description of the test type
procedure Run_Error_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results);
procedure Run_Not_WF_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results);
procedure Run_Valid_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results);
procedure Run_Invalid_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results);
-- Run a single test, for each of the possible test category
function Trim (Str : String) return String;
-- Remove all leading white space characters in Str
function Test_URI
(Descr : Test_Description; URI : Unbounded_String) return String;
-- Compute the URI for the test
----------
-- Trim --
----------
function Trim (Str : String) return String is
S : Integer := Str'First;
begin
while S <= Str'Last
and then (Str (S) = ' ' or else Str (S) = ASCII.LF)
loop
S := S + 1;
end loop;
if S <= Str'Last then
return Str (S .. Str'Last);
else
return "";
end if;
end Trim;
----------------
-- Open_Input --
----------------
function Open_Input (XML_File : String) return Input_Source_Access is
Read : Input_Source_Access;
begin
if XML_File'Length > 0 then
if XML_File'Length > 6
and then XML_File (XML_File'First .. XML_File'First + 6) = "http://"
then
Read := new Http_Input;
Open (XML_File, Http_Input (Read.all));
else
Read := new File_Input;
Open (XML_File, File_Input (Read.all));
end if;
-- Base file name should be used as the public Id
Name_Start := XML_File'Last;
while Name_Start >= XML_File'First
and then XML_File (Name_Start) /= '/'
and then XML_File (Name_Start) /= '\'
loop
Name_Start := Name_Start - 1;
end loop;
Set_Public_Id (Read.all, XML_File (Name_Start + 1 .. XML_File'Last));
-- Full name is used as the system id
Set_System_Id (Read.all, XML_File);
else
Read := new File_Input;
Open ("test.xml", File_Input (Read.all));
end if;
return Read;
exception
when Ada.Text_IO.Name_Error =>
return null;
end Open_Input;
---------------------
-- Run_Single_Test --
---------------------
procedure Run_Single_Test (XML_File : String; Edition : XML_Versions) is
Read : Input_Source_Access;
Reader : My_Tree_Reader;
begin
Read := Open_Input (XML_File);
if Read = null then
return;
end if;
Set_XML_Version (Reader, Edition);
Set_Feature (Reader, Namespace_Feature, Support_Namespaces);
Set_Feature (Reader, Namespace_Prefixes_Feature, Support_Namespaces);
Set_Feature (Reader, Validation_Feature, Validate);
Set_Feature (Reader, Test_Valid_Chars_Feature, Valid_Chars);
Set_Symbol_Table (Reader, Symbols); -- optional, for efficiency
Parse (Reader, Read.all);
if Reader.Had_Error then
Put_Line (Reader.Error_Msg.all);
end if;
Close (Read.all);
Free (Reader.Error_Msg);
Unchecked_Free (Read);
if Must_Normalize then
Normalize (Get_Tree (Reader));
end if;
if not Silent then
if Dump then
DOM.Core.Nodes.Dump (Get_Tree (Reader), With_URI => With_URI);
else
Write
(Stream => Stream (Current_Output),
N => Get_Tree (Reader),
Print_Comments => Print_Comments,
Print_XML_Declaration => Print_XML_PI,
With_URI => With_URI,
EOL_Sequence => EOL.all,
Pretty_Print => Pretty_Print,
Encoding => Encoding_Out,
Collapse_Empty_Nodes => Collapse_Empty_Nodes);
end if;
end if;
Free (Reader);
exception
when E : XML_Fatal_Error =>
if Reader.Had_Error then
Put_Line (Reader.Error_Msg.all);
end if;
Put_Line (Exception_Message (E));
end Run_Single_Test;
-----------
-- Image --
-----------
function Image (Num : Integer; Width : Natural) return String is
Str : constant String := Integer'Image (Num);
begin
if Str'Length < Width then
return (1 .. Width - Str'Length => ' ') & Str;
else
return Str;
end if;
end Image;
--------------------
-- Parse_Disabled --
--------------------
procedure Parse_Disabled is
File : File_Type;
Line : String (1 .. 1024);
Last : Natural;
begin
Open (File, Mode => In_File, Name => "disable");
while not End_Of_File (File) loop
Get_Line (File, Line, Last);
if Line (1) /= '-' and then Line (1) /= ' ' then
Disabled.Include
(Key => Line (1 .. Last),
New_Item => True);
end if;
end loop;
Close (File);
exception
when Name_Error =>
null;
end Parse_Disabled;
-------------------
-- Run_Testsuite --
-------------------
procedure Run_Testsuite is
Input : File_Input;
Tests : Tree_Reader;
N, Top : Node;
Count : Testcases_Results := (others => (others => 0));
Total : Natural;
begin
Parse_Disabled;
Set_Symbol_Table (Tests, Symbols); -- optional, for efficiency
Open ("tests/xmlconf.xml", Input);
Parse (Tests, Input);
Close (Input);
Top := Get_Element (Get_Tree (Tests));
N := First_Child (Top);
while N /= null loop
if Node_Name (N) = "TESTCASES" then
Run_Testcases (N, Get_Attribute (N, "xml:base"), Count);
elsif Node_Type (N) = Element_Node then
Put_Line ("Unknown node in xmlconf.xml: " & Node_Name (N));
raise Program_Error;
end if;
N := Next_Sibling (N);
end loop;
New_Line;
New_Line;
Put_Line ("Release: " & Get_Attribute (Top, "PROFILE"));
if not Run_XML_1_1_Tests then
Put_Line ("N/A: XML 1.1 tests");
end if;
if not Show_Invalid_Encoding then
Put_Line ("N/A: tests with encoding unknown to XML/Ada");
end if;
Put_Line
("+-----------+--------+---------+---------+"
& "---------+---------+--------+----+");
Put_Line
("| | Total | Success | Failure |"
& " N/A | XML 1.1 | Encod. | IE |");
Put_Line
("+-----------+--------+---------+---------+"
& "---------+---------+--------+----+");
for T in Count'Range (1) loop
declare
Pref : constant String := Test_Prefix (T);
begin
Put ("| " & Pref & (1 .. 9 - Pref'Length => ' ') & " |");
end;
Total := 0;
for T2 in Count'Range (2) loop
Total := Total + Count (T, T2);
end loop;
Put_Line
(Image (Total, 7)
& " |" & Image (Count (T, Result_Success), 8)
& " |" & Image (Count (T, Result_Failure), 8)
& " |" & Image (Count (T, Result_Ignore), 8)
& " |" & Image (Count (T, Result_XML_1_1), 8)
& " |" & Image (Count (T, Result_Encoding), 7)
& " |" & Image (Count (T, Result_IE), 3) & " |");
end loop;
Put_Line
("+-----------+--------+---------+---------+"
& "---------+---------+--------+----+");
Free (Tests);
end Run_Testsuite;
-------------------
-- Get_Attribute --
-------------------
function Get_Attribute (N : Node; Attribute : String) return String is
Attr : constant Node := Get_Named_Item (Attributes (N), Attribute);
begin
if Attr = null then
return "";
else
return Node_Value (Attr);
end if;
end Get_Attribute;
-------------------
-- Run_Testcases --
-------------------
procedure Run_Testcases
(N : Node; Base : String; Results : in out Testcases_Results)
is
Test : Node := First_Child (N);
Descr : Test_Description;
begin
Put_Line ("Profile: " & Get_Attribute (N, "PROFILE"));
Descr.Base := To_Unbounded_String (Base);
while Test /= null loop
if Node_Name (Test) = "TEST" then
if Get_Attribute (Test, "TYPE") = "valid" then
Descr.Test_Type := Type_Valid;
elsif Get_Attribute (Test, "TYPE") = "invalid" then
Descr.Test_Type := Type_Invalid;
elsif Get_Attribute (Test, "TYPE") = "not-wf" then
Descr.Test_Type := Type_Not_WF;
elsif Get_Attribute (Test, "TYPE") = "wf" then
Descr.Test_Type := Type_WF;
elsif Get_Attribute (Test, "TYPE") = "error" then
Descr.Test_Type := Type_Error;
else
Put_Line ("Invalid test type: " & Get_Attribute (Test, "TYPE"));
raise Program_Error;
end if;
Descr.ID := To_Unbounded_String (Get_Attribute (Test, "ID"));
Descr.Description := To_Unbounded_String
(Node_Value (First_Child (Test)));
Descr.URI := To_Unbounded_String (Get_Attribute (Test, "URI"));
Descr.Section := To_Unbounded_String
(Get_Attribute (Test, "SECTIONS"));
Descr.Output := To_Unbounded_String
(Get_Attribute (Test, "OUTPUT"));
Descr.Version := To_Unbounded_String
(Get_Attribute (Test, "VERSION"));
Descr.Namespace := Get_Attribute (Test, "NAMESPACE") /= "no";
if Get_Attribute (Test, "EDITION") = "1 2 3 4" then
Descr.Edition := XML_1_0_Fourth_Edition;
else
Descr.Edition := XML_1_0_Fifth_Edition;
end if;
Run_Test
(Descr => Descr,
Entities => Get_Attribute (Test, "ENTITIES"),
Results => Results);
elsif Node_Name (Test) = "TESTCASES" then
Run_Testcases (Test, Base, Results);
elsif Node_Type (Test) = Element_Node then
Put_Line
(Standard_Error, "Unknown child of TEST: " & Node_Name (Test));
raise Program_Error;
end if;
Test := Next_Sibling (Test);
end loop;
end Run_Testcases;
--------------
-- Test_URI --
--------------
function Test_URI
(Descr : Test_Description; URI : Unbounded_String) return String
is
ID : constant String := To_String (Descr.ID);
S_URI : constant String := To_String (URI);
Base : constant String := To_String (Descr.Base);
begin
if Base'Length = 0 then
if ID'Length > 8
and then ID (ID'First .. ID'First + 7) = "rmt-ns11"
then
return Normalize_Pathname
(Name => S_URI,
Directory => "tests/eduni/namespaces/1.1",
Resolve_Links => False);
elsif ID'Length > 8
and then ID (ID'First .. ID'First + 7) = "rmt-ns10"
then
return Normalize_Pathname
(Name => S_URI,
Directory => "tests/eduni/namespaces/1.0",
Resolve_Links => False);
elsif ID'Length > 6
and then ID (ID'First .. ID'First + 6) = "rmt-e2e"
then
return Normalize_Pathname
(Name => S_URI,
Directory => "tests/eduni/errata-2e",
Resolve_Links => False);
elsif ID'Length > 3
and then ID (ID'First .. ID'First + 3) = "rmt-"
then
return Normalize_Pathname
(Name => S_URI,
Directory => "tests/eduni/xml-1.1",
Resolve_Links => False);
else
return "tests/" & S_URI;
end if;
elsif Base (Base'Last) = '/' then
return Normalize_Pathname
(Name => S_URI,
Directory => "tests/" & To_String (Descr.Base),
Resolve_Links => False);
else
return Normalize_Pathname
(Name => S_URI,
Directory => "tests/" & To_String (Descr.Base) & '/',
Resolve_Links => False);
end if;
end Test_URI;
--------------
-- Run_Test --
--------------
procedure Run_Test
(Entities : String;
Descr : Test_Description;
Results : in out Testcases_Results)
is
Path : constant String := Test_URI (Descr, Descr.URI);
Input : Input_Source_Access;
Reader : My_Tree_Reader;
procedure Cleanup;
-- Free locally allocated variables
procedure Cleanup is
begin
if Input /= null then
Close (Input.all);
Unchecked_Free (Input);
end if;
Free (Reader.Error_Msg);
Free (Reader);
end Cleanup;
begin
if not Run_XML_1_1_Tests and then Descr.Version = "1.1" then
Print_Test_Result
(Reader, Descr, Result_XML_1_1, "For XML 1.1", Results);
return;
end if;
if not Run_Disabled_Tests
and then Contains (Disabled, To_String (Descr.ID))
then
Print_Test_Result
(Reader, Descr, Result_Ignore, "Disabled in XML/Ada", Results);
return;
end if;
Input := Open_Input (Path);
if Input = null then
Print_Test_Result
(Reader, Descr, Result_Ignore, "File not found: " & Path,
Results);
return;
end if;
Set_Symbol_Table (Reader, Symbols); -- Optional, for efficiency
Set_XML_Version (Reader, Descr.Edition);
if not Descr.Namespace then
Set_Feature (Reader, Namespace_Feature, False);
Set_Feature (Reader, Namespace_Prefixes_Feature, False);
end if;
Set_Feature (Reader, Test_Valid_Chars_Feature, True);
case Descr.Test_Type is
when Type_Valid =>
Set_Feature (Reader, Validation_Feature, True);
Run_Valid_Test (Reader, Input.all, Descr, Results);
when Type_WF =>
Set_Feature (Reader, Validation_Feature, False);
Run_Valid_Test (Reader, Input.all, Descr, Results);
when Type_Not_WF =>
Set_Feature (Reader, Validation_Feature, False);
Run_Not_WF_Test (Reader, Input.all, Descr, Results);
when Type_Invalid =>
-- Run the test twice (once with validation, once without). Even
-- if the test is unsupported, we still check that XML/Ada find
-- the document as well-formed
declare
Descr2 : Test_Description := Descr;
begin
Descr2.Test_Type := Type_WF;
Run_Test (Entities, Descr2, Results => Results);
end;
Set_Feature (Reader, Validation_Feature, True);
Run_Invalid_Test (Reader, Input.all, Descr, Results);
when Type_Error =>
Set_Feature (Reader, Validation_Feature, False);
Run_Error_Test (Reader, Input.all, Descr, Results);
end case;
Cleanup;
exception
when E : Invalid_Encoding =>
Cleanup;
if Show_Invalid_Encoding then
Print_Test_Result
(Reader, Descr, Result_Failure, "Invalid encoding: "
& Exception_Message (E), Results);
else
Print_Test_Result
(Reader, Descr, Result_Encoding, "Invalid encoding", Results);
end if;
when E : others =>
Cleanup;
Print_Test_Result
(Reader, Descr,
Result_IE, "Unexpected error: " & Exception_Message (E), Results);
end Run_Test;
-----------------
-- Test_Prefix --
-----------------
function Test_Prefix (Typ : Testcase_Type) return String is
begin
case Typ is
when Type_Valid => return "XMLv";
when Type_Not_WF => return "XMLnot-wf";
when Type_Invalid => return "XMLi";
when Type_Error => return "XMLerror ";
when Type_WF => return "XMLwf";
end case;
end Test_Prefix;
-----------------------
-- Print_Test_Result --
-----------------------
procedure Print_Test_Result
(Reader : My_Tree_Reader'Class;
Descr : Test_Description;
Result : Result_Type;
Msg : String;
Results : in out Testcases_Results)
is
R : Result_Type := Result;
M : Unbounded_String := To_Unbounded_String (Msg);
begin
if Result = Result_Success then
declare
D : constant String := Diff_Output (Reader, Descr);
begin
if D /= "" then
R := Result_Failure;
Append (M, ASCII.LF & D);
end if;
end;
end if;
case R is
when Result_Success => Put (" OK ");
when Result_Failure => Put (" NOK ");
when Result_Ignore => Put (" NA ");
when Result_IE => Put (" IE ");
when Result_XML_1_1 => Put (" 1.1 ");
when Result_Encoding => Put (" ENC ");
end case;
Results (Descr.Test_Type, R) := Results (Descr.Test_Type, R) + 1;
Put (Test_Prefix (Descr.Test_Type) & " ");
Put (Descr.Edition'Img & " ");
Put_Line ('[' & To_String (Descr.ID) & "] ");
if Verbose then
Put_Line (" " & Test_URI (Descr, Descr.URI));
Put_Line (" Description: [" & To_String (Descr.Section) & "] "
& Trim (To_String (Descr.Description)));
end if;
if M /= "" then
Put_Line (" " & To_String (M));
end if;
end Print_Test_Result;
-----------------
-- Diff_Output --
-----------------
function Diff_Output
(Reader : My_Tree_Reader'Class;
Descr : Test_Description) return String
is
Expected : constant String := Test_URI (Descr, Descr.Output);
use Character_IO;
File : Ada.Text_IO.File_Type;
File2 : Character_IO.File_Type;
File3 : Character_IO.File_Type;
C, Previous, Previous2 : Character := ASCII.NUL;
Last_Written : Character := ASCII.LF;
In_Doctype : Boolean := False;
begin
if Descr.Output = "" then
return "";
end if;
Create (File, Out_File, Cst_Tmp_File1_Name);
Write (Stream => Ada.Text_IO.Text_Streams.Stream (File),
N => Get_Tree (Reader),
Print_Comments => Print_Comments,
Print_XML_Declaration => Print_XML_PI,
With_URI => With_URI,
EOL_Sequence => EOL.all,
Encoding => Encoding_Out,
Collapse_Empty_Nodes => Collapse_Empty_Nodes);
Close (File); -- Automatically adds a newline character at the end
-- Process the expected output by removing the DTD, which
-- is not stored in the DOM tree, and thus cannot be output
Create (File2, Out_File, Cst_Tmp_File2_Name);
Open (File3, In_File, Expected);
while not End_Of_File (File3) loop
Read (File3, C);
if C = 'D'
and then Previous2 = '<'
and then Previous = '!'
then
In_Doctype := True;
Previous := ASCII.NUL;
Previous2 := ASCII.NUL;
elsif In_Doctype
and then C = ASCII.LF
and then Previous = '>'
and then Previous2 = ']'
then
In_Doctype := False;
Previous := ASCII.NUL;
Previous2 := ASCII.NUL;
C := ASCII.NUL; -- Do not print
end if;
if not In_Doctype and then Previous2 /= ASCII.NUL then
Write (File2, Previous2);
Last_Written := Previous2;
end if;
Previous2 := Previous;
Previous := C;
end loop;
if not In_Doctype and then Previous2 /= ASCII.NUL then
Write (File2, Previous2);
Last_Written := Previous2;
end if;
if not In_Doctype and then Previous /= ASCII.NUL then
Write (File2, Previous);
Last_Written := Previous;
end if;
-- Ensure we end up with a newline, since otherwise some diffs will
-- complain on some systems
if Last_Written /= ASCII.LF then
if Directory_Separator = '\' then
Write (File2, ASCII.CR);
end if;
Write (File2, ASCII.LF);
end if;
Close (File3);
Close (File2);
declare
Status : aliased Integer;
D : constant String := Get_Command_Output
(Command => "diff",
Arguments => (1 => Tmp_File2_Name, 2 => Tmp_File1_Name),
Input => "",
Status => Status'Access,
Err_To_Out => True);
begin
if Status /= 0 then
return D;
end if;
end;
-- Can't delete, since they have been closed. Anyway, it is more
-- convenient to analyze the output.
-- Delete (File2);
-- Delete (File);
return "";
end Diff_Output;
--------------------
-- Run_Error_Test --
--------------------
procedure Run_Error_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results) is
begin
Parse (Reader, Input);
if Reader.Had_Error then
Print_Test_Result
(Reader, Descr, Result_Success, Reader.Error_Msg.all, Results);
else
Print_Test_Result (Reader, Descr, Result_Failure, "", Results);
end if;
exception
when E : XML_Fatal_Error =>
Print_Test_Result
(Reader, Descr, Result_Failure,
"Unexpected Fatal_Error, must have Error" & ASCII.LF
& Exception_Message (E), Results);
end Run_Error_Test;
---------------------
-- Run_Not_WF_Test --
---------------------
procedure Run_Not_WF_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results) is
begin
Parse (Reader, Input);
Print_Test_Result (Reader, Descr, Result_Failure, "", Results);
exception
when E : XML_Fatal_Error =>
Print_Test_Result
(Reader, Descr, Result_Success, Exception_Message (E), Results);
end Run_Not_WF_Test;
--------------------
-- Run_Valid_Test --
--------------------
procedure Run_Valid_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results) is
begin
Parse (Reader, Input);
Print_Test_Result (Reader, Descr, Result_Success, "", Results);
exception
when E : XML_Fatal_Error =>
Print_Test_Result
(Reader, Descr, Result_Failure, Exception_Message (E), Results);
end Run_Valid_Test;
----------------------
-- Run_Invalid_Test --
----------------------
procedure Run_Invalid_Test
(Reader : in out My_Tree_Reader'Class;
Input : in out Input_Source'Class;
Descr : Test_Description;
Results : out Testcases_Results) is
begin
Parse (Reader, Input);
if Reader.Had_Error then
Print_Test_Result
(Reader, Descr, Result_Success, Reader.Error_Msg.all, Results);
else
Print_Test_Result
(Reader, Descr, Result_Failure, "", Results);
end if;
exception
when E : XML_Fatal_Error =>
Print_Test_Result
(Reader, Descr, Result_Failure,
"Unexpected Fatal_Error, must have Error" & ASCII.LF
& Exception_Message (E), Results);
end Run_Invalid_Test;
Edition : XML_Versions := XML_1_0;
begin
-- Since we are going to create multiple parsers, we will share the symbol
-- table, which saves on the number of calls to malloc().
-- This is however optional, since a parser would create its own symbol
-- table when appropriate
declare
S : constant Symbol_Table_Access := new Symbol_Table_Record;
begin
Symbols := Symbol_Table_Pointers.Allocate (S);
end;
-- Parse the command line
loop
case Getopt
("silent uri normalize validate dump valid_chars encoding-out: eol:"
& " comments xmlpi collapse nonamespaces auto verbose pretty xml11"
& " edition:")
is
when ASCII.NUL => exit;
when 'e' =>
if Full_Switch = "eol" then
Free (EOL);
if Parameter = "\n" then
EOL := new String'("" & ASCII.LF);
else
EOL := new String'(Parameter);
end if;
elsif Full_Switch = "encoding-out" then
Encoding_Out := Get_By_Name (Parameter);
elsif Full_Switch = "edition" then
Edition := XML_Versions'Value (Parameter);
end if;
when 'x' =>
if Full_Switch = "xmlpi" then
Print_XML_PI := True;
else
Run_XML_1_1_Tests := True;
end if;
when 'c' =>
if Full_Switch = "comments" then
Print_Comments := True;
else
Collapse_Empty_Nodes := True;
end if;
when 's' => Silent := True;
when 'u' => With_URI := True;
when 'v' =>
if Full_Switch = "validate" then
Validate := True;
elsif Full_Switch = "valid_chars" then
Valid_Chars := False;
elsif Full_Switch = "verbose" then
Verbose := True;
end if;
when 'd' =>
Dump := True;
when 'p' =>
Print_XML_PI := True;
Pretty_Print := True;
Collapse_Empty_Nodes := True;
Print_Comments := True;
Free (EOL);
EOL := new String'("" & ASCII.LF);
when 'n' =>
if Full_Switch = "normalize" then
Must_Normalize := True;
else
Support_Namespaces := False;
end if;
when 'a' => Auto_Run := True;
when others => null;
end case;
end loop;
if Auto_Run then
Run_Testsuite;
else
Run_Single_Test (Get_Argument, Edition);
end if;
Free (EOL);
end Testxml;