code:
use vars qw(%result_texis %result_texts %result_trees %result_errors
   %result_indices %result_sectioning %result_nodes %result_menus
   %result_floats %result_converted %result_converted_errors
   %result_elements %result_directions_text);

use utf8;

$result_trees{'text_between_item_itemx'} = {
  'contents' => [
    {
      'args' => [
        {
          'contents' => [
            {
              'extra' => {
                'command' => {}
              },
              'parent' => {},
              'text' => ' ',
              'type' => 'empty_spaces_after_command'
            },
            {
              'cmdname' => 'strong',
              'contents' => [],
              'line_nr' => {
                'file_name' => '',
                'line_nr' => 1,
                'macro' => ''
              },
              'parent' => {},
              'type' => 'command_as_argument'
            },
            {
              'parent' => {},
              'text' => '
',
              'type' => 'space_at_end_block_command'
            }
          ],
          'parent' => {},
          'type' => 'block_line_arg'
        }
      ],
      'cmdname' => 'table',
      'contents' => [
        {
          'contents' => [
            {
              'contents' => [
                {
                  'args' => [
                    {
                      'contents' => [
                        {
                          'extra' => {
                            'command' => {}
                          },
                          'parent' => {},
                          'text' => ' ',
                          'type' => 'empty_spaces_after_command'
                        },
                        {
                          'parent' => {},
                          'text' => 'in item'
                        },
                        {
                          'parent' => {},
                          'text' => '
',
                          'type' => 'spaces_at_end'
                        }
                      ],
                      'parent' => {},
                      'type' => 'misc_line_arg'
                    }
                  ],
                  'cmdname' => 'item',
                  'extra' => {
                    'misc_content' => [
                      {}
                    ],
                    'spaces_after_command' => {}
                  },
                  'line_nr' => {
                    'file_name' => '',
                    'line_nr' => 2,
                    'macro' => ''
                  },
                  'parent' => {}
                },
                {
                  'contents' => [
                    {
                      'contents' => [
                        {
                          'parent' => {},
                          'text' => 'text
'
                        }
                      ],
                      'parent' => {},
                      'type' => 'paragraph'
                    }
                  ],
                  'parent' => {},
                  'type' => 'inter_item'
                },
                {
                  'args' => [
                    {
                      'contents' => [
                        {
                          'extra' => {
                            'command' => {}
                          },
                          'parent' => {},
                          'text' => ' ',
                          'type' => 'empty_spaces_after_command'
                        },
                        {
                          'parent' => {},
                          'text' => 'in itemx'
                        },
                        {
                          'parent' => {},
                          'text' => '
',
                          'type' => 'spaces_at_end'
                        }
                      ],
                      'parent' => {},
                      'type' => 'misc_line_arg'
                    }
                  ],
                  'cmdname' => 'itemx',
                  'extra' => {
                    'misc_content' => [
                      {}
                    ],
                    'spaces_after_command' => {}
                  },
                  'line_nr' => {
                    'file_name' => '',
                    'line_nr' => 4,
                    'macro' => ''
                  },
                  'parent' => {}
                }
              ],
              'parent' => {},
              'type' => 'table_term'
            }
          ],
          'parent' => {},
          'type' => 'table_entry'
        },
        {
          'args' => [
            {
              'contents' => [
                {
                  'extra' => {
                    'command' => {}
                  },
                  'parent' => {},
                  'text' => ' ',
                  'type' => 'empty_spaces_after_command'
                },
                {
                  'parent' => {},
                  'text' => 'table'
                },
                {
                  'parent' => {},
                  'text' => '
',
                  'type' => 'spaces_at_end'
                }
              ],
              'parent' => {},
              'type' => 'misc_line_arg'
            }
          ],
          'cmdname' => 'end',
          'extra' => {
            'command' => {},
            'command_argument' => 'table',
            'spaces_after_command' => {},
            'text_arg' => 'table'
          },
          'line_nr' => {
            'file_name' => '',
            'line_nr' => 5,
            'macro' => ''
          },
          'parent' => {}
        }
      ],
      'extra' => {
        'block_command_line_contents' => [
          [
            {}
          ]
        ],
        'command_as_argument' => {},
        'end_command' => {},
        'spaces_after_command' => {}
      },
      'line_nr' => {},
      'parent' => {}
    }
  ],
  'type' => 'text_root'
};
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[0]{'extra'}{'command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[1]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[2]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[0]{'extra'}{'command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[1]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[2]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'extra'}{'misc_content'}[0] = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'extra'}{'spaces_after_command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[1]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[1]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[1]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[0]{'extra'}{'command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[1]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[2]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'extra'}{'misc_content'}[0] = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'extra'}{'spaces_after_command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[2]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0]{'contents'}[0]{'extra'}{'command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0]{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0]{'contents'}[1]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0]{'contents'}[2]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'extra'}{'command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'extra'}{'spaces_after_command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'args'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1]{'parent'} = $result_trees{'text_between_item_itemx'}{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'extra'}{'block_command_line_contents'}[0][0] = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'extra'}{'command_as_argument'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'extra'}{'end_command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'contents'}[1];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'extra'}{'spaces_after_command'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[0];
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'line_nr'} = $result_trees{'text_between_item_itemx'}{'contents'}[0]{'args'}[0]{'contents'}[1]{'line_nr'};
$result_trees{'text_between_item_itemx'}{'contents'}[0]{'parent'} = $result_trees{'text_between_item_itemx'};

$result_texis{'text_between_item_itemx'} = '@table @strong
@item in item
text
@itemx in itemx
@end table
';

$result_texts{'text_between_item_itemx'} = 'in item
text
in itemx
';

$result_errors{'text_between_item_itemx'} = [
  {
    'error_line' => ':4: @itemx must follow @item
',
    'file_name' => '',
    'line_nr' => 4,
    'macro' => '',
    'text' => '@itemx must follow @item',
    'type' => 'error'
  }
];

1;

repo_name: mthl/texinfo

license: mit


code:
use vars qw(%result_texis %result_texts %result_trees %result_errors
   %result_indices %result_sectioning %result_nodes %result_menus
   %result_floats %result_converted %result_converted_errors
   %result_elements %result_directions_text);

use utf8;

$result_trees{'title_and_itemx_before_item'} = {
  'contents' => [
    {
      'args' => [
        {
          'contents' => [
            {
              'extra' => {
                'command' => {}
              },
              'parent' => {},
              'text' => ' ',
              'type' => 'empty_spaces_after_command'
            },
            {
              'cmdname' => 'emph',
              'contents' => [],
              'line_nr' => {
                'file_name' => '',
                'line_nr' => 1,
                'macro' => ''
              },
              'parent' => {},
              'type' => 'command_as_argument'
            },
            {
              'parent' => {},
              'text' => '
',
              'type' => 'space_at_end_block_command'
            }
          ],
          'parent' => {},
          'type' => 'block_line_arg'
        }
      ],
      'cmdname' => 'table',
      'contents' => [
        {
          'contents' => [
            {
              'contents' => [
                {
                  'parent' => {},
                  'text' => 'Title
'
                }
              ],
              'parent' => {},
              'type' => 'paragraph'
            }
          ],
          'parent' => {},
          'type' => 'before_item'
        },
        {
          'contents' => [
            {
              'contents' => [
                {
                  'args' => [
                    {
                      'contents' => [
                        {
                          'extra' => {
                            'command' => {}
                          },
                          'parent' => {},
                          'text' => ' ',
                          'type' => 'empty_spaces_after_command'
                        },
                        {
                          'parent' => {},
                          'text' => 'in itemx'
                        },
                        {
                          'parent' => {},
                          'text' => '
',
                          'type' => 'spaces_at_end'
                        }
                      ],
                      'parent' => {},
                      'type' => 'misc_line_arg'
                    }
                  ],
                  'cmdname' => 'itemx',
                  'extra' => {
                    'misc_content' => [
                      {}
                    ],
                    'spaces_after_command' => {}
                  },
                  'line_nr' => {
                    'file_name' => '',
                    'line_nr' => 3,
                    'macro' => ''
                  },
                  'parent' => {}
                }
              ],
              'parent' => {},
              'type' => 'table_term'
            }
          ],
          'parent' => {},
          'type' => 'table_entry'
        },
        {
          'args' => [
            {
              'contents' => [
                {
                  'extra' => {
                    'command' => {}
                  },
                  'parent' => {},
                  'text' => ' ',
                  'type' => 'empty_spaces_after_command'
                },
                {
                  'parent' => {},
                  'text' => 'table'
                },
                {
                  'parent' => {},
                  'text' => '
',
                  'type' => 'spaces_at_end'
                }
              ],
              'parent' => {},
              'type' => 'misc_line_arg'
            }
          ],
          'cmdname' => 'end',
          'extra' => {
            'command' => {},
            'command_argument' => 'table',
            'spaces_after_command' => {},
            'text_arg' => 'table'
          },
          'line_nr' => {
            'file_name' => '',
            'line_nr' => 4,
            'macro' => ''
          },
          'parent' => {}
        }
      ],
      'extra' => {
        'block_command_line_contents' => [
          [
            {}
          ]
        ],
        'command_as_argument' => {},
        'end_command' => {},
        'spaces_after_command' => {}
      },
      'line_nr' => {},
      'parent' => {}
    }
  ],
  'type' => 'text_root'
};
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[0]{'extra'}{'command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[1]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[2]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[0]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[0]{'extra'}{'command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[1]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[2]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'extra'}{'misc_content'}[0] = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[1];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'extra'}{'spaces_after_command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'args'}[0]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[1]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[0]{'extra'}{'command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[1]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[2]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'extra'}{'command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'extra'}{'spaces_after_command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'args'}[0]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2]{'parent'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'extra'}{'block_command_line_contents'}[0][0] = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[1];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'extra'}{'command_as_argument'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[1];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'extra'}{'end_command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'contents'}[2];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'extra'}{'spaces_after_command'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[0];
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'line_nr'} = $result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'args'}[0]{'contents'}[1]{'line_nr'};
$result_trees{'title_and_itemx_before_item'}{'contents'}[0]{'parent'} = $result_trees{'title_and_itemx_before_item'};

$result_texis{'title_and_itemx_before_item'} = '@table @emph
Title
@itemx in itemx
@end table
';

$result_texts{'title_and_itemx_before_item'} = 'Title
in itemx
';

$result_errors{'title_and_itemx_before_item'} = [
  {
    'error_line' => ':3: warning: @itemx should not begin @table
',
    'file_name' => '',
    'line_nr' => 3,
    'macro' => '',
    'text' => '@itemx should not begin @table',
    'type' => 'warning'
  }
];

1;


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}

use Test::More;

BEGIN { plan tests => 7; }

use Texinfo::Parser qw(parse_texi_text);
use Texinfo::Common;

ok(1, "modules loading");

my ($before, $after, $braces_count)
  = Texinfo::Common::_find_end_brace(" aa (bbb ()ccc)(g))j (gg", 1);
is ($before, " aa (bbb ()ccc)(g))", "before with brace closed");
is ($after, "j (gg", "after with brace closed");
ok ($braces_count == 0, "braces count 0 with brace closed");
my $string_no_close = " kjsdf ( k)lj(";
($before, $after, $braces_count)
  = Texinfo::Common::_find_end_brace($string_no_close, 2);
ok (($braces_count == 3 and $before eq $string_no_close and !defined($after)),
    "more braces opened");
my $string_no_brace = " other ";
($before, $after, $braces_count)
  = Texinfo::Common::_find_end_brace($string_no_brace, 1);
ok (($braces_count == 1 and $before eq $string_no_brace and !defined($after)),
  "no brace in text");
my $string_open_brace_and_text = " (other ";
($before, $after, $braces_count)
  = Texinfo::Common::_find_end_brace($string_open_brace_and_text, 1);
ok (($braces_count == 2 and $before eq $string_open_brace_and_text
     and !defined($after)), "more braces opened and text");

sub run_test($$$$)
{
  my $in = shift;
  my $initial_brace_count = shift;
  my $ref_braces_count = shift;
  my $name = shift;

  my $tree = parse_texi_text(undef, $in);

  my $braces_count
    = Texinfo::Common::_count_opened_tree_braces($tree, $initial_brace_count);
  if (!defined($ref_braces_count)) {
    print STDERR " --> $name ($in): $braces_count\n";
  } else {
    is ($braces_count, $ref_braces_count, $name);
  }
}

# Note: these tests are disabled because the code doesn't look at
# parentheses nested inside commands anymore.

# run_test('@code{(sdffsd)} other @code{(gg} ))', 1, 0, 'brace in code');
# run_test('@code{(sdffsd)) aaa}', 1, 0, 'too much braces');
# run_test(' aaa) @asis{)}  @code{( (}', 2, 0, 'more reopened');
# run_test(' aaa) @asis{}  @code{( (}', 2, 3, 'still open');


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}

use Test::More;

BEGIN { plan tests => 8; }

use Texinfo::Transformations;
use Texinfo::Parser qw(parse_texi_text);
use Texinfo::Convert::Texinfo;

ok(1, "modules loading");

my $tree = parse_texi_text(undef, '@raisesections
@section truc
');

my $section = $tree->{'contents'}->[1];
my @correct_level_offset_commands
 = Texinfo::Transformations::_correct_level($section, $tree->{'contents'}->[0]);

# 2 because there is also an empty line
ok (scalar(@correct_level_offset_commands) == 2,"one lowersection");
ok ($correct_level_offset_commands[0]->{'cmdname'} eq 'lowersection' ,
    "command is lowersection");

$tree = parse_texi_text(undef, '@lowersections
@lowersections
@chapter truc
');
$section = $tree->{'contents'}->[1];
@correct_level_offset_commands
   = Texinfo::Transformations::_correct_level($section, $tree->{'contents'}->[0], -1);
ok (scalar(@correct_level_offset_commands) == 4,"two lowersection");
ok ($correct_level_offset_commands[0]->{'cmdname'} eq 'lowersection' ,
    "command is lowersection");

sub test_correction($$$)
{
  my $in = shift;
  my $out = shift;
  my $name = shift;
  my $tree = parse_texi_text(undef, $in);
  my ($corrected_content, $added_sections)
      = Texinfo::Transformations::fill_gaps_in_sectioning($tree);
  $tree->{'contents'} = $corrected_content;
  {
  local $Data::Dumper::Purity = 1;
  #local $Data::Dumper::Maxdepth = 2;
  local $Data::Dumper::Indent = 1;
  #print STDERR Data::Dumper->Dump([$tree]);
  #print STDERR Data::Dumper->Dump([$corrected_content]);
  }
  my $texi_result = Texinfo::Convert::Texinfo::convert({'contents' => $corrected_content});
  if (!defined($out)) {
    print STDERR " --> $name:\n$texi_result";
  } else {
    is($texi_result, $out, $name);
  }
}
test_correction('@chapter chap
@subsection sub
','@chapter chap
@unnumberedsec @asis{}

@subsection sub
', 'simple completed tree');

my $raisesections_lowersection_no_correction_text = '@raisesections
@section sec
@lowersections
@lowersections
@chapter chap
';
test_correction($raisesections_lowersection_no_correction_text,
  $raisesections_lowersection_no_correction_text,
  'raisesections and lowersection, no correction');

test_correction('@raisesections
@section sec
@lowersections
@lowersections
@lowersections
@chapter chap
', '@raisesections
@section sec
@lowersections
@lowersections
@lowersections
@raisesection
@raisesection
@unnumberedsec @asis{}

@lowersection
@lowersection
@chapter chap
', 'raisesections lowersection with correction');


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}

use Test::More;

BEGIN { plan tests => 12; }

use Texinfo::Parser qw(parse_texi_text);
#use Texinfo::Convert::Texinfo;
use Texinfo::Common;
use Data::Dumper;

ok(1, "modules loading");

sub test_is_empty($$$;$)
{
  my $name = shift;
  my $is_empty = shift;
  my $in = shift;
  my $do_not_ignore_index_entries = shift;
  my $tree = parse_texi_text(undef, $in);
  my $result = Texinfo::Common::is_content_empty($tree, $do_not_ignore_index_entries);
  if (not defined($is_empty)) {
    print STDERR " --> $name: $result\n";
  } else {
    is($result, $is_empty, $name);
  }
}

test_is_empty('empty', 1, '');
test_is_empty('spaces', 1, '  ');
test_is_empty('lines', 1, '

  ');
test_is_empty('text', 0, 'truc'."\n");
test_is_empty('heading', 0, '@heading truc'."\n");
test_is_empty('index ignored', 1, '@cindex index'."\n");
test_is_empty('index not ignored', 0, '@cindex index'."\n", 1);
test_is_empty('ignored misc', 1, '@defindex idx'."\n");
test_is_empty('ignored misc then text', 0, '@alias lang=lisp

@AA{}.
');
test_is_empty('@ignore', 1, '@ignore
truc

@end ignore
');
test_is_empty('block command', 0, '@itemize @bullet
@item truc
@end itemize
');

done_testing();


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}

use Test::More;

BEGIN { plan tests => 6; }

use Texinfo::Parser qw(parse_texi_text);
use Texinfo::Common qw(protect_hashchar_at_line_beginning);
use Texinfo::Convert::Texinfo;

use Data::Dumper;

ok(1);

sub run_test($$$;$)
{
  my $in = shift;
  my $out = shift;
  my $name = shift;
  my $error_message = shift;

  my $parser = Texinfo::Parser::parser();
  my $tree = $parser->parse_texi_text($in, 1);

  my $corrected_tree =
    $parser->Texinfo::Common::protect_hashchar_at_line_beginning($tree);

  if (defined($error_message)) {
    my ($errors, $errors_count) = $parser->errors();
    if (!$error_message) {
      if ($errors and scalar(@$errors)) {
        print STDERR " --error-> $errors->[0]->{'error_line'}";
      } else {
        print STDERR "No message\n";
      }
    } else {
      if ($errors and scalar(@$errors)) {
        is($error_message, $errors->[0]->{'error_line'}, "error message: $name");
      } else {
        ok(0, "error message: $name");
      }
    }
  }

  my $texi_result = Texinfo::Convert::Texinfo::convert($corrected_tree);

  if (!defined($out)) {
    print STDERR " --> $name:\n$texi_result";
  } else {
    is ($texi_result, $out, $name);
  }
}

run_test ('# line 4 "ggggg"
and
 # line 5 "fff"
# 46
# 3 4

# line 4 "bbb"
# 7 "aaaa"
', '@hashchar{} line 4 "ggggg"
and
 @hashchar{} line 5 "fff"
@hashchar{} 46
# 3 4

@hashchar{} line 4 "bbb"
@hashchar{} 7 "aaaa"
', 'two paragraphs');

run_test ('
@example
# line 5 "fff"
aaa

b

# line 4 "bbb"
# 7 "aaaa"
@end example
', '
@example
@hashchar{} line 5 "fff"
aaa

b

@hashchar{} line 4 "bbb"
@hashchar{} 7 "aaaa"
@end example
', 'in example');

run_test ('
@table @asis
@item truc

# line 4 "bbb"
@end table

@itemize
# 7 "aaaa"
@item # line 5 "fff"
# 6 "ff"
@end itemize
', '
@table @asis
@item truc

@hashchar{} line 4 "bbb"
@end table

@itemize
@hashchar{} 7 "aaaa"
@item @hashchar{} line 5 "fff"
@hashchar{} 6 "ff"
@end itemize
', 'in block commands');

run_test('
@macro mymacro {}
# line 20 "ff"
@end macro
', '
@macro mymacro {}
# line 20 "ff"
@end macro
', 'in raw command', ':2: warning: could not protect hash character in @macro
');

#{
#  local $Data::Dumper::Purity = 1;
#  local $Data::Dumper::Indent = 1;
#
#  print STDERR Data::Dumper->Dump([$tree]);
#}


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}

use Test::More;
BEGIN { plan tests => 6; };

use Texinfo::Convert::Text;
use Texinfo::Parser;
use Texinfo::Structuring;
use Test::Deep;

ok(1, "modules loading");

my $tree = Texinfo::Parser::parse_texi_line(undef, '@copyright{} @quotedblbase{}');
my $result = Texinfo::Convert::Text::convert($tree, {'sort_string' => 1});
is ($result, 'C ,,', 'sort no encoding');

$result = Texinfo::Convert::Text::convert($tree, {'sort_string' => 1,
                                      'enabled_encoding' => 'utf-8'});

is ($result, "\x{00A9} \x{201E}", 'sort utf-8');

$result = Texinfo::Convert::Text::convert($tree, {'sort_string' => 1,
                                      'enabled_encoding' => 'iso-8859-1'});

is ($result, "\x{00A9} ,,", 'sort iso-8859-1');

my $parser = Texinfo::Parser::parser();
$tree = $parser->parse_texi_text('@node Top

@cindex !
@cindex e
@cindex E
@cindex ``
@cindex @~e
@cindex
@cindex aaaaaaaaaaaa
@cindex @l{}
');

my ($index_names, $merged_indices) =
   $parser->indices_information();
my $index_entries = Texinfo::Structuring::merge_indices($index_names);
my $sorted_index_entries
  = Texinfo::Structuring::sort_indices($parser, $index_entries, $index_names);

my @entries = ();
foreach my $entry (@{$sorted_index_entries->{'cp'}}) {
  push @entries, $entry->{'key'};
}

# e is before E because they are equal and e appears before E in the document
my @entries_ref = ('!', '"', 'aaaaaaaaaaaa', 'e', 'E', 'e~', 'l');

cmp_deeply (\@entries, \@entries_ref, 'sorted index entries');

my $sorted_index_entries_by_letter
  = Texinfo::Structuring::sort_indices_by_letter($parser, $index_entries,
                                                 $index_names);

my @letter_entries_ref = (
   {'!' => [ '!' ]},
   {'"' => [ '"' ]},
   {'A' => [ 'aaaaaaaaaaaa' ]},
   {'E' => [ 'e', 'E', 'e~']},
   {'L' => [ 'l' ]},
);

my @letter_entries;
foreach my $letter (@{$sorted_index_entries_by_letter->{'cp'}}) {
  #my $letter_entry = {'letter' => $letter->{'letter'}};
  my $letter_entry = {};
  push @letter_entries, $letter_entry;
  foreach my $entry (@{$letter->{'entries'}}) {
    push @{$letter_entry->{$letter->{'letter'}}}, $entry->{'key'};
  }
}

{
local $Data::Dumper::Purity = 1;
local $Data::Dumper::Maxdepth = 2;
local $Data::Dumper::Indent = 1;
#print STDERR "".Data::Dumper->Dump([$sorted_index_entries_by_letter])."\n";
#foreach my $letter (@{$sorted_index_entries_by_letter->{'cp'}}) {
#  print STDERR "AAA $letter->{'letter'} ".join('|',keys(%$letter))."\n";
#}
# print STDERR "".Data::Dumper->Dump([\@letter_entries])."\n";
}

cmp_deeply (\@letter_entries, \@letter_entries_ref, 'by letter index entries');


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}
use Test::More;

BEGIN { plan tests => 3; }

use Texinfo::Parser;
use Texinfo::Convert::Texinfo;
use Data::Dumper;
#use Text::Diff;

ok(1, "modules loading");

my $text = '@setfilename some@@file.ext

@node top
@top in @code{top}

@set truc blah@@@

@menu
Something

* chapter::    description
* name: other chapter.
* lone node::
@end menu

@node chapter
@chapter chap

@part part
@node other chapter, lone node, chapter, Top
@chapter other chap

@node lone node, ,other chapter, Top

@vtable @code
@item item
@end vtable

@multitable @columnfractions 0.8 0.2
@end multitable

@multitable {trc} {bidule}
@item truc @tab bidule
@end multitable

@deffn a {b} c d
@end deffn

@float label, type
@caption{float caption}
@end float

@listoffloats type

@acronym{ABC, a b ccc}.

@cindex cindex

@printindex cp

@quotation trc
@author an authoe
@author second
T
@end quotation

';

my $tree = Texinfo::Parser::parse_texi_text(undef, $text);
my $reference_associations = {};
my $copy = Texinfo::Common::copy_tree($tree, undef);

my $texi_tree = Texinfo::Convert::Texinfo::convert($tree);

is ($text, $texi_tree, "tree to texi and original match");

my $texi_copy = Texinfo::Convert::Texinfo::convert($copy);
is ($texi_copy, $texi_tree, "tree and copy to texi match");

#{
#  local $Data::Dumper::Purity = 1;
#  local $Data::Dumper::Indent = 1;
#  print STDERR Data::Dumper->Dump([$copy]);
#}

1;


code:
# $Id$
# t/* test support for the Perl modules.
#
# Copyright 2010, 2011, 2012, 2013, 2014, 2015
# Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License,
# or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Original author: Patrice Dumas <pertusus@free.fr>

use strict;

use 5.006;

BEGIN {

require Texinfo::ModulePath;
Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);

} # end BEGIN

use Test::More;

use Texinfo::Parser;
use Texinfo::Convert::Text;
use Texinfo::Convert::Texinfo;
use Texinfo::Structuring;
use Texinfo::Convert::Plaintext;
use Texinfo::Convert::Info;
use Texinfo::Convert::HTML;
use Texinfo::Convert::TexinfoXML;
use Texinfo::Convert::DocBook;
use File::Basename;
use File::Copy;
use File::Compare; # standard since 5.004
use Data::Dumper;
use Data::Compare;
use Test::Deep;
use Storable qw(dclone); # standard in 5.007003
#use Data::Diff;
#use Data::Transformer;
#use Struct::Compare;
use Getopt::Long qw(GetOptions);

# File: test_file option.

# FIXME Is it really useful?
use vars qw(%result_texis %result_texts %result_trees %result_errors
   %result_indices %result_sectioning %result_nodes %result_menus
   %result_floats %result_converted %result_converted_errors
   %result_elements %result_directions_text);

my $strings_textdomain = 'texinfo_document';
Locale::Messages->select_package ('gettext_pp');

my $srcdir = $ENV{'srcdir'};
my $locales_srcdir;
if (defined($srcdir)) {
  $srcdir =~ s/\/*$/\//;
  $locales_srcdir = $srcdir;
} else {
  $srcdir = '';
  $locales_srcdir = '.';
}

my $localesdir;
foreach my $dir ("LocaleData", "$locales_srcdir/LocaleData") {
  if (-d $dir) {
    $localesdir = $dir;
  }
}

if (! defined($localesdir)) {
  warn "No locales directory found, some tests will fail\n";
}
Locale::Messages::bindtextdomain ('texinfo_document', $localesdir);

my $generated_texis_dir = 't_texis';

my $input_files_dir = $srcdir."t/input_files/";

our $output_files_dir = 't/output_files/';
foreach my $dir ('t', 't/results', $output_files_dir) {
  my $error;
  # to avoid a race conditon, first create the dir then test that it
  # exists
  mkdir $dir or $error = $!;
  if (! -d $dir) {
    die "mkdir $dir: $error\n";
  }
}

my $include_reference_dir = 't/include_reference';
my $include_dir = 't/include_dir';
if (! -d $include_dir) {
  mkdir $include_dir or die "mkdir $include_dir: $!\n";
  if (opendir DIR, $include_reference_dir) {
    my @files = grep {-f "$include_reference_dir/$_"} readdir DIR;
    closedir DIR;
    foreach my $file (@files) {
      copy ("$include_reference_dir/$file", "$include_dir/$file")
        or die "Copy $include_reference_dir/$file $include_dir/$file failed: $!\n";
    }
  } else {
    die "Opendir $include_reference_dir failed: $!\n";
  }
}

ok(1);

our %formats = (
  'plaintext' => \&convert_to_plaintext,
  'file_plaintext' => \&convert_to_plaintext,
  'info' => \&convert_to_info,
  'file_info' => \&convert_to_info,
  'html' => \&convert_to_html,
  'file_html' => \&convert_to_html,
  'html_text' => \&convert_to_html,
  'xml' => \&convert_to_xml,
  'file_xml' => \&convert_to_xml,
  'docbook' => \&convert_to_docbook,
  'file_docbook' => \&convert_to_docbook,
);

our %extensions = (
  'plaintext' => 'txt',
  'html_text' => 'html',
  'xml' => 'xml',
  'docbook' => 'dbk',
);

my %xml_converter_defaults
    = Texinfo::Convert::TexinfoXML::converter_defaults(undef, undef);
my $XML_DTD_VERSION = $xml_converter_defaults{'TEXINFO_DTD_VERSION'};

my %outfile_preamble = (
  'docbook' => ['<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
  <!ENTITY tex "TeX">
  <!ENTITY latex "LaTeX">
]>
'. "<book lang=\"en\">\n", "</book>\n"],
  'xml' => ['<?xml version="1.0"?>
'."<!DOCTYPE texinfo PUBLIC \"-//GNU//DTD TexinfoML V${XML_DTD_VERSION}//EN\" \"http://www.gnu.org/software/texinfo/dtd/${XML_DTD_VERSION}/texinfo.dtd\">
".'<texinfo xml:lang="en">
', "</texinfo>\n"],
 'html_text' => ['<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="tp">
<style type="text/css">
<!--
a.summary-letter {text-decoration: none}
blockquote.indentedblock {margin-right: 0em}
blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
blockquote.smallquotation {font-size: smaller}
div.display {margin-left: 3.2em}
div.example {margin-left: 3.2em}
div.lisp {margin-left: 3.2em}
div.smalldisplay {margin-left: 3.2em}
div.smallexample {margin-left: 3.2em}
div.smalllisp {margin-left: 3.2em}
kbd {font-style: oblique}
pre.display {font-family: inherit}
pre.format {font-family: inherit}
pre.menu-comment {font-family: serif}
pre.menu-preformatted {font-family: serif}
pre.smalldisplay {font-family: inherit; font-size: smaller}
pre.smallexample {font-size: smaller}
pre.smallformat {font-family: inherit; font-size: smaller}
pre.smalllisp {font-size: smaller}
span.nocodebreak {white-space: nowrap}
span.nolinebreak {white-space: nowrap}
span.roman {font-family: serif; font-weight: normal}
span.sansserif {font-family: sans-serif; font-weight: normal}
ul.no-bullet {list-style: none}
-->
</style>
</head>

<body>
',
'</body>
</html>
']
);

our $arg_generate;
our $arg_debug;
our $arg_complete;
our $arg_output;
our $nr_comparisons = 8;

Getopt::Long::Configure("gnu_getopt");
GetOptions('g|generate' => \$arg_generate, 'd|debug=i' => \$arg_debug,
           'c|complete' => \$arg_complete, 'o|output' => \$arg_output);

our $arg_test_case = shift @ARGV;

sub protect_perl_string($)
{
  my $string = shift;
  $string =~ s/\\/\\\\/g;
  $string =~ s/'/\\'/g;
  return $string;
}

sub compare_dirs_files($$;$)
{
  my $dir1 = shift;
  my $dir2 = shift;
  my $ignore_files = shift;

  my %dir1_files;
  my %dir2_files;
  my @errors;
  my %ignored_files_hash;
  foreach my $ignored_file (@$ignore_files) {
    $ignored_files_hash{$ignored_file} = 1;
  }
  if (opendir(DIR1, $dir1)) {
    my @files = readdir (DIR1);
    foreach my $file (@files) {
      next if (! -r "$dir1/$file" or ! -f "$dir1/$file"
               or $ignored_files_hash{$file});
      $dir1_files{$file} = 1;
    }
    closedir (DIR1);
  } else {
    push @errors, "readdir $dir1: $!";
  }
  if (opendir(DIR2, $dir2)) {
    my @files = readdir (DIR2);
    foreach my $file (@files) {
      next if (! -r "$dir2/$file" or ! -f "$dir2/$file"
               or $ignored_files_hash{$file});
      $dir2_files{$file} = 1;
    }
    closedir (DIR2);
  } else {
    push @errors, "readdir $dir2: $!";
  }
  if (scalar(@errors)) {
    return \@errors;
  }
  foreach my $file (sort(keys(%dir1_files))) {
    if ($dir2_files{$file}) {
      my $status = compare("$dir1/$file", "$dir2/$file");
      if ($status) {
        push @errors, "$dir1/$file and $dir2/$file differ: $status";
      }
      delete $dir2_files{$file};
    } else {
      push @errors, "No $file in $dir2";
    }
  }
  foreach my $file (sort(keys(%dir2_files))) {
    push @errors, "No $file in $dir1"
  }
  if (scalar(@errors)) {
    return \@errors;
  } else {
    return undef;
  }
}

#my $errors = compare_dirs_files('a', 'b',['nnn']);
#if ($errors) {
#  foreach my $error (@$errors) {
#    warn $error."\n";
#  }
#}

sub unlink_dir_files($;$)
{
  my $dir = shift;
  my $ignore_files = shift;
  my %ignored_files_hash;
  foreach my $ignored_file (@$ignore_files) {
    $ignored_files_hash{$ignored_file} = 1;
  }
  if (opendir(DIR, $dir)) {
    my @files = readdir (DIR);
    foreach my $file (@files) {
      next if (! -f "$dir/$file"
               or $ignored_files_hash{$file});
      unlink "$dir/$file" or warn "Could not unlink $dir/$file: $!\n";
    }
    closedir (DIR);
  } else {
    warn "readdir $dir: $!";
  }
}

#my $remove_parent = sub {my $h = shift; delete $h->{'parent'}};
#my $transformer = Data::Transformer->new('hash'=>$remove_parent);
sub remove_keys($$;$);
sub remove_keys($$;$)
{
  my $root = shift;
  my $deleted_keys = shift;
  my $been_there = shift;
  return undef if (!defined($root));
  if (!defined($been_there)) {
    #print STDERR "First call: $root\n";
    $root = dclone ($root);
    #print STDERR Data::Dumper->Dump([$root]);
    $been_there = {};
  }
  #print STDERR "remove_keys: $root\n";
  if (ref($root) eq 'HASH') {
    foreach my $key (@$deleted_keys) {
      if (exists($root->{$key})) {
        delete ($root->{$key});
        #print STDERR "Deleted $root $key\n";
      }
    }
    $been_there->{$root} = 1;
    foreach my $key (keys(%$root)) {
      next if (!defined($root->{$key}) or !ref($root->{$key})
               or (ref($root->{$key}) ne 'HASH'
                    and ref($root->{$key}) ne 'ARRAY')
               or exists($been_there->{$root->{$key}}));
      #print STDERR "Recurse in $root $key\n";
      remove_keys($root->{$key}, $deleted_keys, $been_there);
    }
  } elsif (ref($root) eq 'ARRAY') {
    $been_there->{$root} = 1;
    foreach my $element (@$root) {
      next if (!defined($element) or !ref($element)
               or (ref($element) ne 'HASH'
                    and ref($element) ne 'ARRAY')
               or exists($been_there->{$element}));

      remove_keys($element, $deleted_keys, $been_there);
    }
  }
  return $root;
}

sub cmp_trimmed($$$$)
{
  my $compared = shift;
  my $reference = shift;
  my $deleted_keys = shift;
  my $test_name = shift;
  my $trimmed = remove_keys($compared, $deleted_keys);
no warnings 'recursion';
  Test::Deep::cmp_deeply($trimmed, $reference, $test_name);
}

sub new_test($;$$$)
{
  my $name = shift;
  my $generate = shift;
  my $debug = shift;
  my $test_formats = shift;
  my $test = {'name' => $name, 'generate' => $generate,
              'DEBUG' => $debug, 'test_formats' => $test_formats};

  if ($generate) {
    mkdir "t/results/$name" if (! -d "t/results/$name");
  }
  bless $test;
  return $test;
}

my @contents_keys = ('contents', 'args', 'parent', 'line_nr', 'node_content',
  'nodes_manuals', 'misc_content', 'invalid_nesting',
  'block_command_line_contents', 'spaces_after_command');
my @menus_keys = ('menu_next', 'menu_up', 'menu_prev', 'menu_up_hash');
my @sections_keys = ('section_next', 'section_prev', 'section_up',
  'section_childs', 'associated_node', 'part_associated_section',
  'toplevel_prev', 'toplevel_next', 'toplevel_up');
my @node_keys = ('node_next', 'node_prev', 'node_up', 'menus',
  'associated_section');
my %avoided_keys_tree;
our @avoided_keys_tree = (@sections_keys, @menus_keys, @node_keys,
   'menu_child', 'element_next', 'directions', 'page_next', 'remaining_args');
foreach my $avoided_key(@avoided_keys_tree) {
  $avoided_keys_tree{$avoided_key} = 1;
}
sub filter_tree_keys { [grep {!$avoided_keys_tree{$_}} ( sort keys %{$_[0]} )] }

#my @avoided_compare_tree = (@avoided_keys_tree, 'parent', 'node_tree');

my %avoided_keys_sectioning;
my @avoided_keys_sectioning = ('section_next', @contents_keys, @menus_keys,
  @node_keys, 'menu_child', 'toplevel_next');
foreach my $avoided_key(@avoided_keys_sectioning) {
  $avoided_keys_sectioning{$avoided_key} = 1;
}
sub filter_sectioning_keys { [grep {!$avoided_keys_sectioning{$_}}
   ( sort keys %{$_[0]} )] }

my %avoided_keys_nodes;
my @avoided_keys_nodes = (@sections_keys, @contents_keys, @menus_keys);
foreach my $avoided_key(@avoided_keys_nodes) {
  $avoided_keys_nodes{$avoided_key} = 1;
}
sub filter_nodes_keys { [grep {!$avoided_keys_nodes{$_}}
   ( sort keys %{$_[0]} )] }
#my @avoided_compare_nodes = (@avoided_keys_nodes, 'node_up', 'node_prev');

my %avoided_keys_menus;
my @avoided_keys_menus = (@sections_keys, @contents_keys, @node_keys);
foreach my $avoided_key(@avoided_keys_menus) {
  $avoided_keys_menus{$avoided_key} = 1;
}
sub filter_menus_keys { [grep {!$avoided_keys_menus{$_}}
   ( sort keys %{$_[0]} )] }

my %avoided_keys_floats;
my @avoided_keys_floats = (@sections_keys, @contents_keys, @node_keys,
                           @menus_keys);
foreach my $avoided_key(@avoided_keys_floats) {
  $avoided_keys_floats{$avoided_key} = 1;
}
sub filter_floats_keys { [grep {!$avoided_keys_floats{$_}}
   ( sort keys %{$_[0]} )] }

my %avoided_keys_elements;
my @avoided_keys_elements = (@contents_keys, @sections_keys, @node_keys,
  'element_next', 'element_prev');
foreach my $avoided_key(@avoided_keys_elements) {
  $avoided_keys_elements{$avoided_key} = 1;
}
sub filter_elements_keys {[grep {!$avoided_keys_elements{$_}}
   ( sort keys %{$_[0]} )] }

sub set_converter_option_defaults($$$)
{
  my $converter_options = shift;
  my $parser_options = shift;
  my $format = shift;
  $converter_options = {} if (!defined($converter_options));
  if (!defined($converter_options->{'expanded_formats'})) {
    $converter_options->{'expanded_formats'} = [$format];
  }
  return $converter_options;
}

sub close_files($)
{
  my $converter = shift;
  my $converter_unclosed_files = $converter->converter_unclosed_files();
  if ($converter_unclosed_files) {
    foreach my $unclosed_file (keys(%$converter_unclosed_files)) {
      if (!close($converter_unclosed_files->{$unclosed_file})) {
        # FIXME or die?
        warn(sprintf("tp_utils.pl: error on closing %s: %s\n",
                    $converter_unclosed_files->{$unclosed_file}, $!));
      }
    }
  }
}

sub convert_to_plaintext($$$$$$;$)
{
  my $self = shift;
  my $test_name = shift;
  my $format = shift;
  my $tree = shift;
  my $parser = shift;
  my $parser_options = shift;
  my $converter_options = shift;
  $converter_options
    = set_converter_option_defaults($converter_options,
                                    $parser_options, $format);
  if (!defined($converter_options->{'OUTFILE'})
      and defined($converter_options->{'SUBDIR'})) {
    $converter_options->{'OUTFILE'}
      = $converter_options->{'SUBDIR'}.$test_name.".txt";
  }

  my $converter =
     Texinfo::Convert::Plaintext->converter({'DEBUG' => $self->{'DEBUG'},
                                             'parser' => $parser,
                                             'output_format' => 'plaintext',
                                             %$converter_options });
  my $result;
  if ($converter_options->{'OUTFILE'} eq '') {
    $result = $converter->convert($tree);
  } else {
    $result = $converter->output($tree);
    close_files($converter);
    $result = undef if (defined($result and $result eq ''));
  }
  my ($errors, $error_nrs) = $converter->errors();
  return ($errors, $result);
}

sub convert_to_info($$$$$;$)
{
  my $self = shift;
  my $test_name = shift;
  my $format = shift;
  my $tree = shift;
  my $parser = shift;
  my $parser_options = shift;
  my $converter_options = shift;
  # FIXME plaintext too?
  $converter_options
    = set_converter_option_defaults($converter_options,
                                    $parser_options, $format);

  my $converter =
     Texinfo::Convert::Info->converter ({'DEBUG' => $self->{'DEBUG'},
                                         'parser' => $parser,
                                         'output_format' => 'info',
                                          %$converter_options });
  my $result = $converter->output($tree);
  close_files($converter);
  die if (!defined($converter_options->{'SUBDIR'}) and !defined($result));
  my ($errors, $error_nrs) = $converter->errors();
  return ($errors, $result);
}

sub convert_to_html($$$$$$;$)
{
  my $self = shift;
  my $test_name = shift;
  my $format = shift;
  my $tree = shift;
  my $parser = shift;
  my $parser_options = shift;
  my $converter_options = shift;
  $converter_options
    = set_converter_option_defaults($converter_options,
                                    $parser_options, 'html');

  $converter_options->{'SPLIT'} = 0
    if ($format eq 'html_text'
        and !defined($parser_options->{'SPLIT'})
        and !defined($converter_options->{'SPLIT'}));
  if (!defined($converter_options->{'SIMPLE_MENU'})
       and $parser_options->{'SIMPLE_MENU'}) {
    $converter_options->{'SIMPLE_MENU'} = 1;
  }
  my $converter =
     Texinfo::Convert::HTML->converter ({'DEBUG' => $self->{'DEBUG'},
                                         'parser' => $parser,
                                         'output_format' => 'html',
                                          %$converter_options });
  my $result;
  if ($format eq 'html_text') {
    $result = $converter->convert($tree);
  } else {
    $result = $converter->output($tree);
    close_files($converter);
  }
  die if (!defined($converter_options->{'SUBDIR'}) and !defined($result));
  my ($errors, $error_nrs) = $converter->errors();
  return ($errors, $result);
}

sub convert_to_xml($$$$$$;$)
{
  my $self = shift;
  my $test_name = shift;
  my $format = shift;
  my $tree = shift;
  my $parser = shift;
  my $parser_options = shift;
  my $converter_options = shift;
  $converter_options
    = set_converter_option_defaults($converter_options,
                                    $parser_options, 'xml');

  my $converter =
     Texinfo::Convert::TexinfoXML->converter ({'DEBUG' => $self->{'DEBUG'},
                                         'parser' => $parser,
                                         'output_format' => 'texinfoxml',
                                          %$converter_options });

  my $result;
  if (defined($converter_options->{'OUTFILE'})
      and $converter_options->{'OUTFILE'} eq '') {
    $result = $converter->convert($tree);
  } else {
    $result = $converter->output($tree);
    close_files($converter);
    $result = undef if (defined($result and $result eq ''));
  }
  my ($errors, $error_nrs) = $converter->errors();
  return ($errors, $result);
}

sub convert_to_docbook($$$$$$;$)
{
  my $self = shift;
  my $test_name = shift;
  my $format = shift;
  my $tree = shift;
  my $parser = shift;
  my $parser_options = shift;
  my $converter_options = shift;
  $converter_options
    = set_converter_option_defaults($converter_options,
                                    $parser_options, 'docbook');

  my $converter =
     Texinfo::Convert::DocBook->converter ({'DEBUG' => $self->{'DEBUG'},
                                         'parser' => $parser,
                                         'output_format' => 'docbook',
                                          %$converter_options });
  my $result;
  if (defined($converter_options->{'OUTFILE'})
      and $converter_options->{'OUTFILE'} eq '') {
    $result = $converter->convert($tree);
  } else {
    $result = $converter->output($tree);
    close_files($converter);
    $result = undef if (defined($result and $result eq ''));
  }
  my ($errors, $error_nrs) = $converter->errors();
  return ($errors, $result);
}

# Run a single test case.  Each test case is an array
# [TEST_NAME, TEST_TEXT, PARSER_OPTIONS, CONVERTER_OPTIONS]
sub test($$)
{
  my $self = shift;
  my $test_case = shift;

  my $parser_options = {};
  my $converter_options = undef;
  my ($test_name, $test_text);

  my $tests_count = 0;

  $test_name = shift @$test_case;
  die if (!defined($test_name));
  $test_text = shift @$test_case;
  $parser_options = shift @$test_case if (@$test_case);
  $converter_options = shift @$test_case if (@$test_case);

  if (!defined $parser_options->{'expanded_formats'}) {
    $parser_options->{'expanded_formats'} = [
      'docbook', 'html', 'xml', 'info', 'plaintext'];
    #  'tex' is missed out here so that @ifnottex is expanded
    # in the tests.  Put
    #   {'expanded_formats' => ['tex']}
    # where you need @tex expanded in the t/*.t files.
  }

  my $test_file;
  if ($parser_options->{'test_file'}) {
    $test_file = $input_files_dir . $parser_options->{'test_file'};
    delete $parser_options->{'test_file'};
  }
  my $test_input_file_name;
  if ($parser_options->{'test_input_file_name'}) {
    $test_input_file_name = $parser_options->{'test_input_file_name'};
    delete $parser_options->{'test_input_file_name'};
  }
  my $split = '';
  if ($parser_options->{'test_split'}) {
    $split = $parser_options->{'test_split'};
    if ($split ne 'node' and $split ne 'section') {
      warn "In test_utils.pl, test_split should be node or section, not $split\n";
    }
    delete $parser_options->{'test_split'};
  }
  my %todos;
  if ($parser_options->{'todo'}) {
    %todos = %{$parser_options->{'todo'}};
    delete $parser_options->{'todo'};
  }
  my $split_pages = '';
  if ($parser_options->{'test_split_pages'}) {
    $split_pages = $parser_options->{'test_split_pages'};
    delete $parser_options->{'test_split_pages'};
  }

  my @tested_formats;
  if ($parser_options and $parser_options->{'test_formats'}) {
    push @tested_formats, @{$parser_options->{'test_formats'}};
    delete $parser_options->{'test_formats'};
  #} elsif ($self->{'test_formats'}) {
  #  push @tested_formats, @{$self->{'test_formats'}};
  }

  my $parser = Texinfo::Parser->parser({'TEST' => 1,
                                        'include_directories' => [
                                          't/include_dir/',
                                          't/include/',
                                          $srcdir.'t/include/'],
                                        'DEBUG' => $self->{'DEBUG'},
                                       %$parser_options});
  # take the initial values to record only if there is something new
  my $initial_index_names = $parser->indices_information();
  # do a copy to compare the values and not the references
  $initial_index_names = dclone($initial_index_names);
  print STDERR "  TEST $test_name\n" if ($self->{'DEBUG'});
  my $result;
  if (!$test_file) {
    $result = $parser->parse_texi_text($test_text, 1);
    if (defined($test_input_file_name)) {
      $parser->{'info'}->{'input_file_name'} = $test_input_file_name;
    }
  } else {
    $result = $parser->parse_texi_file($test_file);
  }
  Texinfo::Structuring::associate_internal_references($parser);
  my $floats = $parser->floats_information();

  my $structure = Texinfo::Structuring::sectioning_structure($parser, $result);
  if ($structure) {
    Texinfo::Structuring::warn_non_empty_parts($parser);
  }

  Texinfo::Structuring::number_floats($floats);

  my $top_node = Texinfo::Structuring::nodes_tree($parser);

  my ($errors, $error_nrs) = $parser->errors();
  my $index_names = $parser->indices_information();
  # FIXME maybe it would be good to compare $merged_index_entries?
  my $merged_index_entries
     = Texinfo::Structuring::merge_indices($index_names);

  # only print indices information if it differs from the default
  # indices
  my $indices;
  my $trimmed_index_names = remove_keys($index_names, ['index_entries']);
  $indices->{'index_names'} = $trimmed_index_names
    unless (Data::Compare::Compare($trimmed_index_names, $initial_index_names));

  my $sorted_index_entries;
  if ($merged_index_entries) {
    $sorted_index_entries
      = Texinfo::Structuring::sort_indices_by_letter($parser,
                                                     $merged_index_entries,
                                                     $index_names);
  }
  if ($parser_options->{'SIMPLE_MENU'}) {
    require Texinfo::Transformations;
    $parser->Texinfo::Transformations::set_menus_to_simple_menu();
  }

  my $converted_text = Texinfo::Convert::Text::convert($result, {'TEST' => 1});

  my %converted;
  my %converted_errors;
  $converter_options = {} if (!defined($converter_options));
  foreach my $format (@tested_formats) {
    if (defined($formats{$format})) {
      my $format_converter_options = {%$converter_options};
      my $format_type = $format;
      if ($format_type =~ s/^file_//) {
        # the information that the results is a file is passed
        # through $format_converter_options->{'SUBDIR'} being defined
        my $base = "t/results/$self->{'name'}/$test_name/";
        my $test_out_dir;
        if ($self->{'generate'}) {
          $test_out_dir = 'res_'.$format_type;
          if (-d $base."$test_out_dir/") {
             unlink_dir_files("t/results/$self->{'name'}/$test_name/$test_out_dir/");
          }
        } else {
          $test_out_dir = 'out_'.$format_type;
        }
        if (!defined($format_converter_options->{'SUBDIR'})) {
          mkdir ($base)
            if (! -d $base);
          if (! -d $base."$test_out_dir/") {
            mkdir ($base."$test_out_dir/");
          } else {
            # remove any files from previous runs
            unlink glob ($base."$test_out_dir/*");
          }
          $format_converter_options->{'SUBDIR'}
             = $base."$test_out_dir/";
        }
      } elsif (!defined($format_converter_options->{'OUTFILE'})) {
        $format_converter_options->{'OUTFILE'} = '';
      }
      ($converted_errors{$format}, $converted{$format})
           = &{$formats{$format}}($self, $test_name, $format_type,
                                  $result, $parser,
                                  $parser_options, $format_converter_options);
      $converted_errors{$format} = undef if (!@{$converted_errors{$format}});
      if (defined($converted{$format}) and $format =~ /^file_/) {
        warn "Warning: output generated for $format by $test_name\n";
      }
      #print STDERR "$format: \n$converted{$format}";

      # output converted result and errors in files if $arg_output is set
      if ($arg_output) {
        mkdir ("$output_files_dir/$self->{'name'}")
          if (! -d "$output_files_dir/$self->{'name'}");
        my $extension;
        if ($extensions{$format}) {
          $extension = $extensions{$format};
        } else {
          $extension = $format;
        }

        if (defined ($converted{$format})) {
          my $outfile = "$output_files_dir/$self->{'name'}/$test_name.$extension";
          if (!open (OUTFILE, ">$outfile")) {
            warn "Open $outfile: $!\n";
          } else {
            my $info = $parser->global_informations();
            if ($info and $info->{'perl_encoding'}) {
              binmode(OUTFILE, ":encoding($info->{'perl_encoding'})");
            }
            if ($outfile_preamble{$format}) {
              print OUTFILE $outfile_preamble{$format}->[0];
            }
            print OUTFILE $converted{$format};
            if ($outfile_preamble{$format}) {
              print OUTFILE $outfile_preamble{$format}->[1];
            }
            close (OUTFILE) or warn "Close $outfile: $!\n";
          }
        }
        if ($converted_errors{$format}) {
          my $errors_file
            = "$output_files_dir/$self->{'name'}/${test_name}_$extension.err";
          if (!open (ERRFILE, ">$errors_file")) {
            warn "Open $errors_file: $!\n";
          } else {
            foreach my $error_message (@{$converted_errors{$format}}) {
              print ERRFILE $error_message->{'error_line'};
            }
            close (ERRFILE) or warn "Close $errors_file: $!\n";
          }
        }
      }
    }
  }
  my $directions_text;
  # re-associate top level command with the document_root in case a converter
  # split the document, by resetting their 'parent' key.
  # It may be noticed that this is only done after all conversions.  This
  # means that depending on the order of converters call, trees feed to
  # converters may have a document_root as top level command parent or
  # elements.  All the converters will have the document_root as argument.
  Texinfo::Structuring::_unsplit($result);
  my $elements;
  if ($split eq 'node') {
    $elements = Texinfo::Structuring::split_by_node($result);
  } elsif ($split eq 'section') {
    $elements = Texinfo::Structuring::split_by_section($result);
  }
  if ($split) {
    Texinfo::Structuring::elements_directions($parser, $elements);
    $directions_text = '';
    foreach my $element (@$elements) {
      $directions_text .= Texinfo::Structuring::_print_directions($element);
    }
  }
  if ($split_pages) {
    Texinfo::Structuring::split_pages($elements, $split_pages);
  }

  my $file = "t/results/$self->{'name'}/$test_name.pl";
  my $new_file = $file.'.new';

  my $split_result;
  if ($elements) {
    $split_result = $elements;
  } else {
    $split_result = $result;
  }

  {
    local $Data::Dumper::Purity = 1;
    local $Data::Dumper::Indent = 1;

    my $out_file = $new_file;
    $out_file = $file if ($self->{'generate'});

    mkdir "t/results/$self->{'name'}" if (! -d "t/results/$self->{'name'}");
    open (OUT, ">$out_file") or die "Open $out_file: $!\n";
    binmode (OUT, ":encoding(utf8)");
    print OUT 'use vars qw(%result_texis %result_texts %result_trees %result_errors '."\n".
              '   %result_indices %result_sectioning %result_nodes %result_menus'."\n".
              '   %result_floats %result_converted %result_converted_errors '."\n".
              '   %result_elements %result_directions_text);'."\n\n";
    print OUT 'use utf8;'."\n\n";

    #print STDERR "Generate: ".Data::Dumper->Dump([$result], ['$res']);
    my $out_result;
    {
      local $Data::Dumper::Sortkeys = \&filter_tree_keys;
      $out_result = Data::Dumper->Dump([$split_result], ['$result_trees{\''.$test_name.'\'}']);
    }
    my $texi_string_result = Texinfo::Convert::Texinfo::convert($result);
    $out_result .= "\n".'$result_texis{\''.$test_name.'\'} = \''
          .protect_perl_string($texi_string_result)."';\n\n";
    $out_result .= "\n".'$result_texts{\''.$test_name.'\'} = \''
          .protect_perl_string($converted_text)."';\n\n";
    {
      local $Data::Dumper::Sortkeys = \&filter_sectioning_keys;
      $out_result .=  Data::Dumper->Dump([$structure],
                           ['$result_sectioning{\''.$test_name.'\'}'])."\n"
        if ($structure);
    }
    if ($top_node) {
      {
        local $Data::Dumper::Sortkeys = \&filter_nodes_keys;
         $out_result .=  Data::Dumper->Dump([$top_node], ['$result_nodes{\''.$test_name.'\'}'])."\n";
      }
      {
        local $Data::Dumper::Sortkeys = \&filter_menus_keys;
         $out_result .=  Data::Dumper->Dump([$top_node], ['$result_menus{\''.$test_name.'\'}'])."\n";
      }
    }
    {
      local $Data::Dumper::Sortkeys = 1;
      $out_result .= Data::Dumper->Dump([$errors], ['$result_errors{\''.$test_name.'\'}']) ."\n\n";
      $out_result .= Data::Dumper->Dump([$indices], ['$result_indices{\''.$test_name.'\'}']) ."\n\n"
         if ($indices);
    }
    if ($floats) {
      local $Data::Dumper::Sortkeys = \&filter_floats_keys;
      $out_result .= Data::Dumper->Dump([$floats], ['$result_floats{\''.$test_name.'\'}']) ."\n\n";
    }
    if ($elements) {
      local $Data::Dumper::Sortkeys = \&filter_elements_keys;
      $out_result .= Data::Dumper->Dump([$elements], ['$result_elements{\''.$test_name.'\'}']) ."\n\n";
      $out_result .= "\n".'$result_directions_text{\''.$test_name.'\'} = \''
        .protect_perl_string($directions_text)."';\n\n";
    }
    foreach my $format (@tested_formats) {
      if (defined($converted{$format})) {
        $out_result .= "\n".'$result_converted{\''.$format.'\'}->{\''
          .$test_name.'\'} = \''.protect_perl_string($converted{$format})."';\n\n";
      #print STDERR "$format: \n$converted{$format}";
      }
      if (defined($converted_errors{$format})) {
        local $Data::Dumper::Sortkeys = 1;
        $out_result .= Data::Dumper->Dump([$converted_errors{$format}],
                 ['$result_converted_errors{\''.$format.'\'}->{\''.$test_name.'\'}']) ."\n\n";
        #print STDERR "".Data::Dumper->Dump([$converted_errors{$format}]);
      }
    }

    $out_result .= "1;\n";
    print OUT $out_result;
    close (OUT);
    #if (ref($test_case) ne 'ARRAY') {
    #  my $out_texi_file = "t/results/$self->{'name'}/$test_name.texi";
    #  open (OUT, ">$out_texi_file") or die "Open $out_texi_file: $!\n";
    #  print OUT $texi_string_result;
    #  close (OUT);
    #}

    print STDERR "--> $test_name\n".Texinfo::Convert::Texinfo::convert($result)."\n"
            if ($self->{'generate'});
  }
  if (!$self->{'generate'}) {
    %result_converted = ();
    require "$srcdir$file";

    cmp_trimmed($split_result, $result_trees{$test_name}, \@avoided_keys_tree,
                $test_name.' tree');
    cmp_trimmed($structure, $result_sectioning{$test_name},
                 \@avoided_keys_sectioning, $test_name.' sectioning' );
    cmp_trimmed($top_node, $result_nodes{$test_name}, \@avoided_keys_nodes,
                $test_name.' nodes');
    cmp_trimmed($top_node, $result_menus{$test_name}, \@avoided_keys_menus,
                $test_name.' menus');

    ok (Data::Compare::Compare($errors, $result_errors{$test_name}),
        $test_name.' errors');
    ok (Data::Compare::Compare($indices, $result_indices{$test_name}),
        $test_name.' indices');
    ok (Texinfo::Convert::Texinfo::convert($result) eq $result_texis{$test_name},
         $test_name.' texi');
    if ($todos{'text'}) {
      #TODO: {
        #local $TODO = $todos{'text'};
      SKIP: {
        skip $todos{'text'}, 1;
        ok ($converted_text eq $result_texts{$test_name}, $test_name.' text');
      }
    } else {
      ok ($converted_text eq $result_texts{$test_name}, $test_name.' text');
    }
    $tests_count = $nr_comparisons;
    if (defined($result_directions_text{$test_name})) {
      cmp_trimmed($elements, $result_elements{$test_name},
                  \@avoided_keys_elements, $test_name.' elements');
      $tests_count++;
      ok ($directions_text eq $result_directions_text{$test_name},
          $test_name.' directions text');
      $tests_count++;
    }
    if (@tested_formats) {
      foreach my $format (@tested_formats) {
        my $reference_exists;
        my $format_type = $format;
        if ($format_type =~ s/^file_//) {
          my $base = "t/results/$self->{'name'}/$test_name/";
          my $reference_dir = "$srcdir$base".'res_'.$format_type;
          my $results_dir = $base.'out_'.$format_type;
          if (-d $reference_dir) {
            $reference_exists = 1;
            $tests_count += 1;
            my $errors = compare_dirs_files($reference_dir, $results_dir);
            if ($todos{$format}) {
              #TODO: {
              #  local $TODO = $todos{$format};
              SKIP: {
                skip $todos{$format}, 1;
                ok (!defined($errors), $test_name.' converted '.$format)
                  or diag (join("\n", @$errors));
              }
            } else {
              ok (!defined($errors), $test_name.' converted '.$format)
                or diag (join("\n", @$errors));
            }
          } else {
            print STDERR "\n$format $test_name: \n$results_dir\n";
          }
        } elsif (!defined($result_converted{$format})) {
          my $result;
          if (defined($converted{$format})) {
            $result = $converted{$format};
          } else {
            $result = 'UNDEF'."\n";
          }
          print STDERR "\n$format $test_name:\n$result";
        } else {
          $reference_exists = 1;
          $tests_count += 1;
          if ($todos{$format}) {
            TODO: {
              local $TODO = $todos{$format};
              ok ($converted{$format}
                              eq $result_converted{$format}->{$test_name},
                   $test_name.' converted '.$format);
            }
          } else {
            ok ($converted{$format}
                           eq $result_converted{$format}->{$test_name},
                $test_name.' converted '.$format);
          }
        }
        if ($reference_exists) {
          $tests_count += 1;
          ok (Data::Compare::Compare($converted_errors{$format},
               $result_converted_errors{$format}->{$test_name}),
               $test_name.' errors '.$format);
        }
      #print STDERR "$format: \n$converted{$format}";
      }
    }
    #is (Texinfo::Convert::Texinfo::convert($result), $result_texis{$test_name}, $test_name.' text');
  }
  #exit;
  return $tests_count;
}

# Main entry point for the tests.
#   $NAME - a string, name of test
#   $TEST_CASES - array of sub-tests
#   If $TEST_CASE_NAME is given, only run that test.
#   $GENERATE means to generate reference test results (-g from command line).
#   $DEBUG for debugging.
# The $ARG_COMPLETE variable is the -c option, to create Texinfo files for the
# test cases.
sub run_all($$;$$$)
{
  my $name = shift;
  my $test_cases = shift;
  my $test_case_name = shift;
  my $generate = shift;
  my $debug = shift;

  my $test = new_test($name, $generate, $debug);
  my $ran_tests;
  if (defined($test_case_name)) {
    if ($test_case_name =~ /^\d+$/) {
      $ran_tests = [ $test_cases->[$test_case_name-1] ];
    } else {
      foreach my $test_case (@$test_cases) {
        if ($test_case->[0] eq $test_case_name) {
          $ran_tests = [ $test_case ];
          last;
        }
      }
    }
  } else {
    $ran_tests = $test_cases;
  }

  if (!defined($ran_tests)) {
    die "No test\n";
  }
  my $test_nrs = 0;

  foreach my $test_case (@$ran_tests) {
    if ($arg_complete) {
      $test->output_texi_file($test_case);
    } else {
      $test_nrs += $test->test($test_case);
    }
  }
  if ($generate or $arg_complete) {
    plan tests => 1;
  } else {
    plan tests => (1 + $test_nrs);
  }
}

# Create a Texinfo file for a test case; used when -c option is given.
sub output_texi_file($)
{
  my $self = shift;
  my $test_case = shift;
  my $test_name = shift @$test_case;
  my $test_text = shift @$test_case;
  my $test_options = shift @$test_case;

  my $dir = "$generated_texis_dir/$self->{'name'}/";
  mkdir "$generated_texis_dir/" or die
     unless (-d "$generated_texis_dir/");
  mkdir $dir or die
     unless (-d $dir);
  my $file = "${dir}$test_name.texi";
  open (OUTFILE, ">$file") or die ("Open $file: $!\n");

  my $first_line = "\\input texinfo \@c -*-texinfo-*-";
  if (!defined($test_text)) {
    my $test_file;
    if ($test_options and $test_options->{'test_file'}) {
      $test_file = $input_files_dir . $test_options->{'test_file'};
      if (open (INFILE, $test_file)) {
        my $holdTerminator = $/;
        undef $/;
        $test_text = <INFILE>;
        $/ = $holdTerminator;
      } else {
        die "Open $test_file: $!\n";
      }
      if ($test_text =~ /^\\input texinfo *\@/m
          or $test_text =~ /^\\input texinfo *$/m) {
        $first_line = "";
      }
    }
  }
  my $setfilename;
  if ($test_text =~ /^\@setfilename/m) {
    $setfilename = ''
  } else {
    $setfilename = "\@setfilename $test_name.info\n";
  }
  my $node_top;
  my $top = '';
  if ($test_text =~ /^\@node +top[\s,]/mi or $test_text =~ /^\@node +top *$/mi) {
    $node_top = '';
  } else {
    $node_top = "\@node Top\n";
    unless ($test_text =~ /^\@top\s/m or $test_text =~ /^\@top *$/m) {
      $node_top .= "\@top $test_name\n";
    }
  }
  my $bye = '';
  if ($test_text !~ /^\@bye *$/m) {
    $bye = '@bye';
  }
  print OUTFILE "$first_line

$setfilename
$node_top

$test_text

$bye\n";
  close (OUTFILE) or die "Close $file: $!\n";
}

1;


code:
use strict;

use File::Spec;
BEGIN { if (defined($ENV{'top_srcdir'})) {unshift @INC, File::Spec->catdir($ENV{'top_srcdir'}, 'tp');} }

require 't/test_utils.pl';

my @test_cases = (
['image_inline_or_not',
'@image{A}

Para @image{hh}.

@node Top
@top top

@image{B}

Para @image{jj}.

@example

@image{in_example}

T
@image{in example after text}
@end example

@quotation @image{in_quotation_arg}
@image{in_quotation_content}
@end quotation

@table @asis
@item @image{in_table_item}

@image{in_table_def}

AA @image{in_table_def_para}

@image{in_table_def_after}
@end table

@menu
* @image{node_image}:: @image{image_in_description}
* @image{in_menu_entry_name}: (somewhere)@image{extnode}.

@image{in_menu_comment}
@end menu

@node @image{node_image}
@chapter @image{in_chapter_arg}

T@footnote{
@image{in_footnote}
}

@float F,g

@image{in_float}

@caption{@image{in_caption} PAra @image{in_caption_para}}
@end float
'],
['comments_on_block_command_lines',
'@itemize @c comm
@item itemize it
@end itemize

@itemize x @c comm
@item itemize xit
@end itemize

@itemize @bullet @c comm
@item itemize bulletit
@end itemize

@itemize @bullet{} @c comm
@item itemize bullet with braces
@end itemize

@enumerate @c comm
@item en
@end enumerate

@enumerate a @c comm
@item aen
@end enumerate

@table @asis @c table
@item it
@end table

@quotation @c quot no arg
Quot no arg
@end quotation

@quotation quotarg @c quot arg
Quot arg
@end quotation

@group @c comm
in gr
@end group

@example @c comm
in ex
@end example

@multitable @columnfractions 0.4 0.6 @c comm
@item a @tab b
@end multitable

@multitable {aaa} {bbb} @c c
@item aaa @tab bbb
@end multitable

@float f,g @c comm
In f
@end float

@flushright @c comm
flushright
@end flushright

@raggedright @c comm
raggedright
@end raggedright

'],
['comments_end_lines',
'@itemize
@item itemize it
@end itemize  @c comment itemize

@enumerate
@end enumerate @c comm

@table @asis
@item it
@end table @c table

@quotation
Quot no arg
@end quotation @c quot no arg

@group
in gr
@end group @c comm

@example
in ex
@end example @c comm

@multitable @columnfractions 0.4 0.6
@item a @tab b
@end multitable @c comm

@float f,g
In f
@end float  @c comm

@flushright
flushright
@end flushright @c comm

@raggedright
raggedright
@end raggedright @c comm
'],
['comments_on_misc_command_line',
'@setfilename  comments_on_misc_command_line.info  @c setfilename (text)
@definfoenclose phoo,;,:  @c definfoenclose (number)
@firstparagraphindent none @c c (number)
@raisesections @c raisesections (skipline)
@insertcopying  @comment  (noarg)
@pagesizes 200mm @c pagesizes  (line)
@everyheading @thispage @| aaa @c everyheading (lineraw)

@indent @c indent (skipspace)
Para.
'],
['raw',
'@tex
in <tex>
@end tex

Para
@xml
<in />
@end xml
',
{'expanded_formats' => ['tex', 'xml']}
],
['raw_and_comments',
'@tex  @c comment
in <tex>
@end tex  @comment other comment

Para
@xml @c in xml comment
<in />
@end xml  @comment end xml comment
',
{'expanded_formats' => ['tex', 'xml']}
],
['node_no_section',
'@node Top
'],
['macro_and_args',
'@macro good { aaa, 2b-bb}
@end macro

@macro bad { ggg"@@^_ ff, nnn_b, ccc v}
@end macro
'],
['commands_and_spaces',
'@set  foo   some @value

@setfilename  commands_and_spaces.info

@unmacro  ggg

@clickstyle  @arrow

@cropmarks  after  cropmarks.

@node a ,(b),(c) , (d)

@center  centered

@indent  after indent.

@indent
line after indent

@indent
endof line with spaces line after indent

@image{ a ,b,c , d,e }

@image{ a ,b
,c , d,e }

@quotation  Note
Q
@end quotation

@float  ff , b
f
@caption{ In caption }j.
@shortcaption{Short}  g.
@end float

@multitable  @columnfractions  0.4  0.6
@end multitable

@multitable  {aa b}  { r }  @var{cmd}gg hh j
@end multitable

@verbatim
in verbatim @g
@end verbatim

@tex
in tex
@end  tex

@example
in example
@end  example

@table  @strong
@item  in item
@end   table

T@footnote{  a}.

Math @math{ \\underline{ a, b} }.

@indicateurl{ http://ggg }

@deffn { truc } { machin }  { bidule }  {  chose } {  arg }
T
@end deffn

',
{'expanded_formats' => ['tex'] }
],
['spaces_info_lost',
'@example  text on example line
in bad example
@end  example

@verbatim
in verbatim @g
@end  verbatim
'],
['brace_commands_spaces_end_of_lines',
'@image{
a}

@image{
a}

@image{a,
b}

@image{a,
b}

@image{a,
 b}

@image{a,
 b}
'],
['node_and_bye',
'@node Top

@bye
', {'test_split' => 'section'}],
['lone_bye',
'@bye
'],
);

foreach my $test (@test_cases) {
  $test->[2]->{'test_formats'} = ['xml'];
}

our ($arg_test_case, $arg_generate, $arg_debug);

run_all ('xml_tests', [@test_cases], $arg_test_case,
   $arg_generate, $arg_debug);

1;


code:
# $Id$
# Makefile.am for texinfo/tp/tests.
# Copyright 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# autogenerated list of scripts that only run one test, and lists of
# tests-parser.txt files specifying the tests to run.
include $(srcdir)/Makefile.onetst

$(srcdir)/Makefile.onetst: \
  ../maintain/regenerate_cmd_tests.sh $(test_driving_files_generated_list)
	cd $(srcdir) \
	&& $(SHELL) ../maintain/regenerate_cmd_tests.sh "$@" . \
	  -base '$(base_tests)' \
	  -tex_html '$(tex_html_tests)'

base_tests = formatting htmlxref htmlxref-only_mono htmlxref-only_split \
	     sectioning coverage indices nested_formats contents layout
tex_html_tests = tex_html

DIST_SUBDIRS = many_input_files $(base_tests) $(tex_html_tests)
SUBDIRS = . many_input_files

copy-tests: copy-base
	cd many_input_files && $(MAKE) copy-tests

copy-base:
	$(srcdir)/parser_tests.sh -copy $(base_tests)

copy-tex-html:
	$(srcdir)/parser_tests.sh -copy $(tex_html_tests)
	cd many_input_files && $(MAKE) copy-tex-html

clean-tests:
	$(srcdir)/parser_tests.sh -clean $(base_tests) $(tex_html_tests)

other_tests = \
	t/stdout.sh \
	t/stdout_split.sh

TESTS = $(one_test_files_generated_list) $(other_tests)

AM_TESTS_ENVIRONMENT = srcdir="$(srcdir)"; export srcdir; top_srcdir="$(top_srcdir)"; export top_srcdir; builddir="$(builddir)"; export buildir; top_builddir="$(top_builddir)"; export top_builddir;

all-checks all-check: all
	$(MAKE) $(AM_MAKEFLAGS) check ALL_TESTS=yes

tex-html-checks tex-html-check: all
	$(MAKE) $(AM_MAKEFLAGS) check TEX_HTML_TESTS=yes

# this is in order to have the htmlxref.cnf files in the build dir.
# This is done in this directory to be sure that the files are there
# when check is done in this directory.
# Some files are in 2 directories in order to get the same result
# in both test run locations.
all-local: htmlxref/htmlxref.cnf htmlxref-only_mono/htmlxref.cnf \
 htmlxref-only_split/htmlxref.cnf \
 equivalent_nodes-noderename.cnf sectioning/equivalent_nodes-noderename.cnf \
 unknown_nodes_renamed-noderename.cnf \
 formatting/unknown_nodes_renamed-noderename.cnf coverage_macro-cr.texi

htmlxref/htmlxref.cnf: htmlxref/htmlxref.cnf-ref
	${INSTALL_DATA} $(srcdir)/htmlxref/htmlxref.cnf-ref $@

htmlxref-only_mono/htmlxref.cnf: htmlxref-only_mono/htmlxref.cnf-ref
	${INSTALL_DATA} $(srcdir)/htmlxref-only_mono/htmlxref.cnf-ref $@

htmlxref-only_split/htmlxref.cnf: htmlxref-only_split/htmlxref.cnf-ref
	${INSTALL_DATA} $(srcdir)/htmlxref-only_split/htmlxref.cnf-ref $@

sectioning/equivalent_nodes-noderename.cnf: sectioning/renamednodes.cnf-ref
	${INSTALL_DATA} $(srcdir)/sectioning/renamednodes.cnf-ref $@

equivalent_nodes-noderename.cnf: sectioning/renamednodes.cnf-ref
	${INSTALL_DATA} $(srcdir)/sectioning/renamednodes.cnf-ref $@

formatting/unknown_nodes_renamed-noderename.cnf: formatting/unknown_nodes_renamed-noderename.cnf-ref
	${INSTALL_DATA} $(srcdir)/formatting/unknown_nodes_renamed-noderename.cnf-ref $@

unknown_nodes_renamed-noderename.cnf: formatting/unknown_nodes_renamed-noderename.cnf-ref
	${INSTALL_DATA} $(srcdir)/formatting/unknown_nodes_renamed-noderename.cnf-ref $@

coverage_macro-cr.texi: coverage_macro.texi
	sed 's/$$/\r/' $(srcdir)/coverage_macro.texi > $@

EXTRA_DIST = run_parser_all.sh parser_tests.sh \
 $(one_test_files_generated_list) coverage_macro.texi \
 coverage_macro-cr.texi $(other_tests) reference

DISTCLEANFILES = unknown_nodes_renamed-noderename.cnf \
 equivalent_nodes-noderename.cnf

dist-hook:
	rm -rf `find $(distdir)/reference -name .svn`


code:
$Id$
texinfo/tp/tests/README

  Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016
  Free Software Foundation, Inc.

  Copying and distribution of this README file, with or without
  modification, are permitted in any medium without royalty provided the
  copyright notice and this notice are preserved.

Files anywhere within the texinfo/tp/tests/ subdirectory which have no
other copyright notice are hereby placed in the public domain.

This directory contains tests of the texi2any program.

Prerequisites
=============
To run this testsuite, sed, awk, diff (with -u) are used.
For LaTeX2HTML tests (not run by default), mktemp
understanding the -d option is also required.

Some tests may also require a case insensitive filesystem.

Running the testsuite
=====================
This testsuite can be run one of the following ways:

* Using the makefile rules: "make check" (in this directory)
These tests use the scripts under the test_scripts directory.

* Using ./parser_tests.sh with the directories one want to run the tests
in given as arguments, for example "./parser_tests.sh formatting".

Checking test results
---------------------
The test results are in the out_parser directories; the reference
results are in res_parser directories.  There can be these pairs.
- out_parser/ and res_parser/ for html output in texi2html style;
- out_parser_html/ and res_parser_html/ for html output in texi2any style;
- out_parser_info/ and res_parser_info/ for info results;
and diffs are put in the diffs/ subdir.

For example, to investigate a failure in the
test_scripts/layout_formaatting_docbook.sh test, compare the contents of the
files in the layout_res_parser/formatting_docbook and
layout_out_parser/formatting_docbook directories, e.g.

diff {res,out}_parser/formatting_docbook/formatting.2

Also look in the layout/diffs directory.

If the test results are as expected, copy the output files onto the
reference files.  Otherwise, if they need more investigation, see "Tests
specification" below, to find out what input file, etc. was used for the
test.  Sometimes you need to use "makeinfo -F" to force an output file
to be created.

When running tests via parser_tests.sh or run_parser_all.sh, then
a test failure causes
 F: a_test_directory
to be printed.  If there is a diff with the references, then
 D: a_test_directory
is printed. If there are no reference to compare with, then
 no res: a_test_directory
is printed.

If a whole directory check run using './parser_tests.sh' had no failure,
the directory name is printed followed by a fail; it is followed
by a ok if there was a failure.

The test results are in a directory below the out directories. This
directory name can be considered as the test name. Let's call it a_test
for the remainder of the explanation. The stderr output is in
out_parser/a_test/a_test.2, stdout output is in
out_parser/a_test/a_test.1.  All the commands called are output in
tests.log.

Regenerating test results
=========================

To update the test results, first the tests must be run as above.

Giving -copy as the first argument to ../run_parser_all.sh or
parser_tests.sh (tex_html_tests.sh, which needs TEX_HTML_TESTS or ALL_TESTS
to be set to "yes", but otherwise operates similarly) will cause the
reference results to be copied from the results the last time the tests
were run.  For example, to update the reference results for one
particular test:

$ ./parser_tests.sh -copy formatting
The copy-* make targets update all the references for various large sets
of tests via this method.

Exception: in the many_input_files subdirectory, the *parser*.sh scripts
can't be used for updating.  Instead, the Makefile's copy-tests and
copy-tex-html targets do it directly.

TeX4ht and LaTeX2HTML tests
===========================
The tex4ht and latex2HTML related tests are not run automatically, as
some test results involving latex2HTML or tex4ht depend on the setup and
version of these tools.

These tests may be run by
  make tex-html-checks

For the tests that use latex2html, to avoid the test failing if there is
a dot in the cwd, mktemp is used to create a temporary directory, and
the directory is passed through on the command line.

Tests specification
===================
Test runs are driven by the contents of the tests-parser.txt file in
each subdirectory. This is a line-oriented file. A # starts a
comment, except that the very first line of the file can be, e.g.,
# formats :html
which says which formats to generate.

Otherwise, each non-empty non-comment line describes a test.  The first
word on the line is the test name which corresponds also with the
resulting directory (what we called a_test above).  It is followed by
the source manual name. The source manual name has to have the .texi
extension.  Optionally, additional arguments can be given on the rest of
the line.

So, for example, the line

a_test manual.texi

specifies that for the test a_test, the file manual.texi is processed
and results are put are put in the a_test directory.  The line:

a_test_split_chapter manual.texi --split chapter

specifies that the results of the processing of manual.texi with additional
command line arguments --split chapter will be in the a_test_split_chapter
directory.

Using "texi" as the test name is special. In that case the directory name
is constructed by appending _ followed by the manual name without the .texi
extension to "texi". And the result is not processed normally, but instead
macros are expanded and regions that are not processed removed and the
result is put in a file with the same name as the manual.

texi manual.texi

results in the following: in the directory out_parser/texi_manual the file
manual.texi will have macros expanded and ignored regions removed.

Common .texi
------------
A common .texi file should be in the top-level directory (there is such an
example with coverage_macro.texi).

Init files
----------
Init files are searched for in ../t/init/.

Creating a new test
===================
- choose the subdir here for the new test.  Each subdir only generates
output in one or two formats (according to the `formats' line in
its tests-parser.txt), so if you want to test a particular output
format, use the right place.

- add the line to subdir/tests-parser.txt as described above.
- most probably, create the needed subdir/*.texi file
- cd subdir; ../run_parser_all.sh newtest

This will create subdir/out_parser*/newtest/ with the test results
(as explained above), as well as stdout in newtest.1 and stderr in newtest.2.
Look carefully to be sure they are as they should be.

For XML output, perhaps check validity using the commands in tp/TODO.

When things look good, use the -copy option to create the
subdir/res_parser*/newtest/ subdirs and copy the output files there.

The test run will be logged in subdir/test_log/newtest.log,
including the exact invocation of texi2any, which can alter anything.
For even more, use sh -vx to show exactly what run_parser_all is doing.

When satisfied, add the .texi in subdir/Makefile.am.

Of course commit all the files and try a make check afterward to verify
it gets run, and passes.

See tp/t/README for info about those tests.

path: tp/tests/README


code:
EXTRA_DIST = contents_at_begin.texi contents_at_end.texi \
 contents_in_middle_chapter.texi contents_in_middle_section.texi \
 double_contents.texi double_contents_setcontentsaftertitlepage.texi \
 no_content.texi no_content_setcatpage.texi \
 contents_and_parts.texi \
 res_parser tests-parser.txt

DISTCLEANFILES = tests.log tests.out

distclean-local:
	rm -rf out_parser diffs test_log

dist-hook:
	rm -rf `find $(distdir)/res_parser -name .svn`


code:
\input texinfo.tex    @c -*-texinfo-*-
@setfilename contents_and_parts.info

@node Top
@top top

@menu
* chapter 1 node::
* chapter 2 node::
* chapter 3 node::
@end menu

@part part 1: part 1

@node chapter 1 node
@chapter chapter 1

@node chapter 2 node
@chapter chapter 2

@part part2: part2

@node chapter 3 node
@chapter chapter 3

@contents
@shortcontents

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_at_begin.info

@contents

@node Top
@top Contents at beginning

Content at the beginning.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

The chapter

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_at_end.info

@node Top
@top Contents at end

Content at end.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

The chapter

@contents
@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_in_middle_chapter.info

@node Top
@top Contents in chapter

Content in chapter.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

The chapter with contents
@contents

@menu
* section::
@end menu

@node section
@section section

Section.

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_in_middle_section.info

@node Top
@top Contents in section

Content in section.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

@menu
* section::
* section1::
@end menu

@node section
@section section

The section with contents
@contents

@node section1
@section section 1

Section 1.

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename double_contents.info

@contents

@node Top
@top Double contents

Double contents.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

@contents
The chapter

@menu
* section::
@end menu

@node section
@section section with contents
@contents

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename double_contents_setcontentsaftertitlepage.info

@contents
@setcontentsaftertitlepage

@node Top
@top Double contents

Double contents.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

@contents
The chapter

@menu
* section::
@end menu

@node section
@section section with contents
@contents

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename no_contents.info

@node Top
@top No ccontent

No content.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

The chapter

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename no_contents_setcatpage.info

@node Top
@top No ccontent

No content.

@menu
* chapter::
@end menu

@node chapter
@chapter Chapter 1

The chapter

@bye


code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<title>top</title>

<meta name="description" content="top">
<meta name="keywords" content="top">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="texi2any">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

[ < ]
[ > ]

[Contents]
[Index]
[ ? ]

top

1 chapter 1

2 chapter 2

3 chapter 3

[ << ]
[ < ]
[ Up ]
[ > ]
[ >> ]

[Top]
[Contents]
[Index]
[ ? ]

part 1: part 1

1 chapter 1

[ << ]
[ < ]
[ Up ]
[ > ]
[ >> ]

[Top]
[Contents]
[Index]
[ ? ]

2 chapter 2

[ << ]
[ < ]
[ Up ]
[ > ]
[ >> ]

[Top]
[Contents]
[Index]
[ ? ]

part2: part2

3 chapter 3

[Top]
[Contents]
[Index]
[ ? ]

Table of Contents

part 1: part 1

1 chapter 1

2 chapter 2

part2: part2

3 chapter 3

[Top]
[Contents]
[Index]
[ ? ]

Short Table of Contents

part 1: part 1

1 chapter 1

2 chapter 2

part2: part2

3 chapter 3

[Top]
[Contents]
[Index]
[ ? ]

About This Document

  This document was generated on a sunny day using texi2any.

  The buttons in the navigation panels have the following meaning:

     Button
     Name
     Go to
     From 1.2.3 go to

     [ << ]
    FastBack
    Beginning of this chapter or previous chapter
    1

     [ < ]
    Back
    Previous section in reading order
    1.2.2

     [ Up ]
    Up
    Up section
    1.2

     [ > ]
    Forward
    Next section in reading order
    1.2.4

     [ >> ]
    FastForward
    Next chapter
    2

     [Top]
    Top
    Cover (top) of document

     [Contents]
    Contents
    Table of contents

     [Index]
    Index
    Index

     [ ? ]
    About
    About (help)

  where the  Example  assumes that the current position is at  Subsubsection One-Two-Three  of a document of the following structure:

 1. Section One

1.1 Subsection One-One

...

1.2 Subsection One-Two

1.2.1 Subsubsection One-Two-One

1.2.2 Subsubsection One-Two-Two

1.2.3 Subsubsection One-Two-Three
            <== Current Position

1.2.4 Subsubsection One-Two-Four

1.3 Subsection One-Three

...

1.4 Subsection One-Four

  This document was generated on a sunny day using texi2any.