<chapter id="internals">
  <title>Software Internals</title>
  
  <sect1 id="tour">
    <title>A Tour of &app;</title>
    
    <para>
      The top level of &app; has several libraries, <emphasis>libgnashbase</emphasis>,
      <emphasis>libgnashcore</emphasis>,
      <emphasis>libgnashmedia</emphasis>,
      <emphasis>libgnashamf</emphasis> and
      <emphasis>libgnashrender</emphasis>. There are several utility programs 
      included for debug parsing and processing of SWF movie files,
      and other useful utilities for examining local Shared Objects and
      sniffing LocalConnections.
    </para>
    
    <sect2 id="The Libraries">
      <title>The Libraries</title>
      
      <sect3 id="libbase">
	<title>libgnashbase</title>
	
	<para>
	  Libgnashbase contains support classes used by the rest of the
	  code.This library has no dependencies on any of the other
	  &app; libraries.
	</para>

	<para>
	  &app; makes heavy use of smart pointers, so memory allocations
	  are freed up automatically by the interpreter. Both STL and
	  Boost smart pointers are used.
	</para>	
      </sect3>
      
      <sect3 id="libgnashcore">
	<title>libgnashcore</title>
	<para>
	  Libgnashcore is the guts of the interpreter itself. This is where
	  the main code for the interpreter lives. Included in
	  libcore are the two support libraries for the parser and
	  the core of the virtual machine.
	</para>
      </sect3>

      <sect3 id="libgnashmedia">
	<title>libgnashmedia</title>
	<para>
        Libgnashmedia handles &app;'s decoding of video and audio,
        including both streamed and embedded media.
		Besides the standard SWF formats
		FLV, MPEG4, Nellymoser, ADPCM, MP3 and RAW, &app; can 
		decode other formats supports by Gstreamer or FFmpeg, 
		including the free OGG container and free codecs.
	</para>
</sect3>

      <sect3 id="libgnashsound">
	<title>libgnashsound</title>
    <para>
        This library handles sound output and manages sound objects.
	</para>
      </sect3>

      <sect3 id="libgnashamf">
	<title>libgnashamf</title>
	<para>
	  AMF is the data format used internally by SWF files. This is
	  &app;'s support library to handle AMF data. This is used by
	  the ActionScript classes SharedObject and
	  LocalConnection. This is also used by the NetStream class
	  when using thre RTMP streaming network protocol.
	</para>
      </sect3>
      
      <sect3 id="libgnashbackend">
	<title>libgnashbackend</title>
	
	<para>
	  Libgnashbackend is a library containing the rendering
	  code that glues this display to the &app;. Supported
	  rendering backends are OpenGL, Cairo, and AGG.
	</para>
      </sect3>

      <sect3 id="libgnashpluin">
	<title>libgnashplugin</title>
	
	<para>
	  Libgnashplugin is the Mozilla/Firefox plugin.
	</para>	
      </sect3>

      <sect3 id="libklashpart">
	<title>libklashpart</title>
	
	<para>
	  Libklashpart is the Konqueror plugin.
	</para>	
      </sect3>
    </sect2>


    <sect2 id="apps">
      <title>The Applications</title>
      
      <para>
	    There are currently a few standalone programs in &app;,
        which serve either to assist with &app; development or to play SWF
        movies.
      </para>

      <sect3 id="Gnash">
	<title>The Standalone Player</title>
	
	<para>
	  This is the standalone OpenGL backend used to play
	  movies. There are several command line options and keyboard
	  control keys used by &app;.
	</para>

      </sect3>

      <sect3 id="processor">
	<title>Gprocessor</title>
	
	<para>
	  Gprocessor is used to print out the actions (using the -va
	  option) or the parsing (using the -vp option) of a SWF
	  movie. It is also used to produce the <emphasis>.gsc</emphasis>
	  files that &app; uses to cache data, thereby speeding up the
	  loading of files.
	</para>

      </sect3>
      <sect3 id="soldumper">
	<title>SOLdumper</title>
	
	<para>
	  SOLDumper is a utility program used to find and dump the
	  content of <emphasis>Local Shared Objects</emphasis>, also
	  called &quot;Flash Cookies&quot; by some.
	</para>

      </sect3>
      <sect3 id="dumpshm">
	<title>Dumpshm</title>
	
	<para>
	  Dumpshm is a program used to find and dump the contents of
	  the <emphasis>LocalConnection</emphasis> shared memory segment.
	</para>

      </sect3>
    </sect2>
    
    <sect2 id="plugin">
      <title>The Plugin</title>

      <para>
	The plugin is designed to work within Mozilla or Firefox,
	although there is Konqueror support as well. The plugin uses
	the Mozilla plugin API (NPAPI) to be cross platform, and is
	portable, as well as being well integrated into Mozilla based
	browsers.
      </para>

      <sect3 id="pluginstatus">
	<title>Current Implementation</title>
	<para>
	  The plugin works in a
	  fashion similar to MozPlugger: the standalone player
	  is used instead of using a thread. This gets around the
	  issue of having to maintain a separate player to support the
	  plugin. It also gets around the other issues that &app;
	  itself is not thread safe at this time.
	</para>
      </sect3>

      <sect3 id="gui">
	<title>GUI Support</title>

	<para>
	  Any plugin that wants to display in a browser window needs
	  to be tied into the windowing system of the platform being
	  used. On GNU/Linux systems, Firefox is a GTK2+ application.
	  There is also KDE support through the use of the Klash
	  plugin.
	</para>

	<para>
	  &app; can use either several different GUI toolkits to create the window,
	  and to handle events for the standalone player.
	</para>
	
	<para>
	  The SDL version is more limited, but runs on all
	  platforms, including win32. It has no support for event
	  handling, which means mouse clicks, keyboard presses, and
	  window resizing doesn't work. I personally find the default
	  event handler slow and unresponsive. &app; has support to
	  use fast events, (currently not enabled) which is an SDL
	  hack using a background thread to pump events into the SDL
	  event queue at a much higher rate.
	</para>

	<para>
	  There are a variety of development libraries that build a GUI
	  widget system on top of SDL and OpenGL. The use of these to
	  add menus and dialog boxes to the SDL version is being
	  considered. 
	</para>

	<para>
	  The GTK support is currently the most functional, and the
	  best integrated into Firefox. The performance of this
	  version is better than the SDL version because of the more
	  efficient event handling within GTK. For the best end user
	  experience, use the GTK enabled version.
	</para>

	<para>
	  GTK also allows &app; to have menus and dialog
	  boxes. Currently this is only being utilized in a limited
	  fashion for now. There is a right mouse button menu that
	  allows the user to control the movie being player the same
	  way the existing keyboard commands do.
	</para>

      </sect3>
      
      <sect3 id="Klash">
	<title>Klash</title>
	<para>
	  Klash is MozPlugger type support for KDE's Konqueror web
	  browser. Klash makes &app; a <emphasis>kpart</emphasis>, so it's
	  integrated into KDE better than when using MozPlugger. Klash
	  uses the standalone player, utilizing &app;'s "-x" window
	  plugin command line option.
	</para>

	<para>
	  By default, Klash is not built. To enable building Klash,
	  use the <emphasis>--enable-klash</emphasis> option when
	  configuring. Other than installing, there is nothing else
	  that needs to be done to install Klash.
	</para>
      </sect3>

    </sect2>

    &logging;

  </sect1>

  <sect1 id="soundhandlers">
    <title>Sound handling in &app;</title>

    <para>
        Sound in &app; is handled by libgnashsound. This library takes
        care of interfacing with a sound handler.
    </para>

    <para>
      There are two different settings related to sound support:
      <emphasis>pluginsound</emphasis> and <emphasis>sound</emphasis>. 
      This was done in order to allow the plugin to be independently 
      configured, for instance to block sound from advertisements.
    </para>

    <sect2 id="soundtypes">
      <title>Sound types</title>
      <para>
        Sounds can be divided into two groups: event-sounds and soundstreams.
	Event-sounds are contained in a single SWF frame, but the playtime can
	span multiple frames. Soundstreams can be (and normally are) divided
	between the SWF frames the soundstreams spans. This means that if a
	gotoframe-action jumps to a frame which contains data for a soundstream,
	playback of the stream can be picked up from there. 
      </para>
    </sect2>

     <sect2 id="soundparsing">
      <title>Sound parsing</title>
      <para>
        When &app; parses a SWF-file, it creates a sound handler if possible
	and hands over the sounds to it. Since the event-sounds are contained 
	in one frame, the entire event-sound is retrieved at once, while a 
	soundstream maybe not be completely retrieved before the entire 
	SWF-file has been parsed. But since the entire soundstream doesn't need
	to be present when playback starts, it is not necessary to wait. 
      </para>
    </sect2>

    <sect2 id="soundplayback">
      <title>Sound playback</title>
      <para>
	When a sound is about to be played &app; calls the sound handler, which
	then starts to play the sound and return. All the playing is done by
	threads (in both SDL and Gstreamer), so once 
	started the audio and graphics are not sync'ed with each other, which
	means that we have to trust both the graphic backend and the audio
	backend to play at correct speed. 
      </para>
    </sect2>

    <sect2 id="sdlsound">
      <title>The SDL sound backend</title>
      <para>
	The current SDL sound backend has replaced the original sound 
	handler, based on SDL_mixer, which by design had some limitations, 
	making it difficult to implement needed features such as support 
	for soundstreams. 
	The SDL sound backend supports both event-sounds and soundstreams,
	using &app;'s internal ADPCM, and optionally MP3 support, using
	FFMPEG.
	When it receives sound data it is stored without being decoded, unless
	it is ADPCM, which is decoded in the parser. When playing, backend
	relies on a function callback for retrieving output sound, which is 
	decoded and re-sampled if needed, and all sound output is mixed together.
	The current SDL sound backend was made since &app; needed a working
	sound backend as soon as possible, and since the gstreamer backend at
	the time suffered from bugs and/or lack of features in gstreamer. The
	result was the most complete and best sound handler so far.
	The advantages of the SDL sound handler is speed, and ease of use,
	while its only real disadvantage is that it has to be compiled with
	MP3 support, which some Linux distributions will probably not like...
      </para>
    </sect2>
 
   <sect2 id="gstreamer">
      <title>The Gstreamer backend</title>
      <para>
	The Gstreamer backend, though not complete, supports both soundstreams
	and event-sounds. When receiving sound data it stores it compressed,
	unless if it's ADPCM event-sounds, which it decodes by the parser.
        When the playback starts, the backend sets up a
	Gstreamer bin containing a decoder (and other things needed) and places
	it in a Gstreamer pipeline, which plays the audio. All the sound data is
	not passed at once, but in small chunks, and via callbacks the
	pipeline gets fed. The advantages of the Gstreamer backend is that it
        supports both kinds of sound, it avoids all the legal MP3-stuff, and it
	should be relatively easy to add VORBIS support. The drawbacks are that
	it has longer "reply delay" when starting the playback of a sound, and
	it suffers under some bugs in Gstreamer that are yet to be fixed. 
      </para>
    </sect2>

    <sect2 id="gstreamer-details">
      <title>Detailed description of the Gstreamer backend</title>
      <para>
	Gstreamer uses pipelines, bins and elements. Pipelines are the
	main bin, where all other bins or elements are places. Visually the
	audio pipeline in &app; looks like this: 
      </para>

      <programlisting>
	 ___
	|Bin|_
	|___| \
	 ___   \ _____       ____________
	|Bin|___|Adder|_____|Audio output|
	|___|   |_____|     |____________|
	 ___   /
	|Bin|_/
	|___|

      </programlisting>

      <para>
	There is one bin for each sound which is being played. If a sound is
	played more the once at the same time, multiple bins will be made. The
	bins contains: 
      </para>

      <programlisting>

	|source|---|capsfilter|---|decoder|---|aconverter|---|aresampler|---|volume|

      </programlisting>

      <para>
	In the source element we place parts of the undecoded sound data, and
	when playing the pipeline will pull the data from the element. Via
	callbacks it is refilled if needed. In the capsfilter the data is
	labeled with the format of the data. The decoder (surprise!) decodes
	the data. The audioconverter converts the now raw sound data into a
	format accepted by the adder, all input to the adder must in the same
	format. The audio re-sampler re-samples the raw sound data into a sample
	accepted by the adder, all input to the adder must in the same
	sample rate. The volume element makes it possible to control the volume
	of each sound. 
      </para>

      <para>
	When a sound is done being played it emits a End-Of-Stream-signal
	(EOS), which is caught by an event-handler-callback, which then makes
	sure that the bin in question is removed from the pipeline. When a
	sound is told by &app; to stop playback before it has ended playback,
	we do something (not yet finally implemented), which makes the bin emit
	an EOS, and the event-handler-callback will remove the sound from the
	pipeline. Unfortunately Gstreamer currently has a bug which causes the
	entire pipeline to stop playing when unlinking an element from the
	pipeline; so far no fix is known. 
      </para>

      <para>
	Gstreamer also contains a bug concerning linking multiple elements to
	the adder in rapid succession, which causes to adder to "die" and stop
	the playback. 
      </para>
    </sect2>


  </sect1>

  <sect1 id="testing">
    <title>Testing </title>

     <para>
       <link linkend="runtests">Instructions on running tests</link>
       can be found in the section on building &app;.
     </para>

    <sect2 id="testtools">
      <title>Testing Tools</title>

      <para>
	Currently &app; uses three other tools to help with
	testing. Two of these are free compilers for the SWF
	format. This lets us write simple test cases for &app; to test
	specific features, and to see how the features operate.
      </para>

      <para>
	The primary compiler used at this time is <ulink type="http"
	url="http://ming.sf.net">Ming</ulink>. Since release 0.3,
	<emphasis>Ming</emphasis> includes a command-line compiler,
	<emphasis>makeswf</emphasis>. This allows test case development
        to be done entirely with free tools.
      </para>
      
      <para>
        The other tools are optional.  
	<ulink type="http"
	       url="http://www.gnu.org/software/dejagnu">DejaGnu</ulink>
	is used to run multiple test cases in an automated
	manner. <emphasis>DejaGnu</emphasis> is used by many other <ulink
	type="http" url="http://www.gnu.org">GNU</ulink> projects like 
	<ulink type="http" url="http://gcc.gnu.org">GCC</ulink> and 
	<ulink type="http" url="http://www.samba.org">Samba</ulink>.
      </para>
      
    </sect2>

    <sect2 id="testcases">
      <title>Test Cases</title>
      
      <para>
	ActionScript test cases are located under testsuite/actionscript.all/;
	these are organized in one file for the ActionScript class.
	Other Ming-generated tests are under testsuite/ming-misc.all/;
	these are typically used to test specific tag types.
	Full movies are located in testsuite/movies.all/ and
	sample movies are found in testsuite/samples/.
	Other directories in testsuite/ are (or shall be) used for other
	kind of tests.
      </para>
      
    </sect2>

    <sect2 id="writeastests">
      <title>Writing ActionScript Tests</title>

      <para>
	Writing ActionScript tests is very simple. The
	<emphasis>makeswf</emphasis> compiler makes use of the C preprocessor,
	thus allowing the inclusion of definitions for macros and external 
	files. We use these feature to provide common utilities
	for test units.
      </para>
      
      <para>
	Each test unit sets an <emphasis>rcsid</emphasis> variable, includes the
	<emphasis>check.as</emphasis> file and performs some checks using
	the provided macros. Here is an example:
	
	<programlisting>

	  // This variable will be used by check.as
	  // to show testcase info as part of the test runs.
	  rcsid="Name and version of this testcase, usually the RCS id";
	  
	  #include "check.as"
	  
	  // Test object creation
	  check(new Object() instanceOf Object);
	  
	  // Test parseInt
	  check(isNaN(parseInt('none')));

	  // Test assignment
	  var a = 1;
	  check_equals(a, 1);
	  
	  // .. your tests here ...
	</programlisting>
      </para>
      
      <para>
	The check(expr) macro will <emphasis>trace</emphasis> PASSED or FAILED
	together with the expression being evaluated and the line number
	of the check. This is the format expected by DejaGnu.
      </para>

      <para>
	The <emphasis>check_equals(obtained, expected)</emphasis> macro uses equality operator
	<emphasis>==</emphasis> to check for equality. When possible, use of the
	<emphasis>check_equals()</emphasis> macro is preferred over <emphasis>check()</emphasis>
	because it shows what the actual result was in case of a failure. 
      </para>
      
      <para>
	Additionally, the check.as file provides a transparent way to send
	results to a TextField rather then using trace. This is very useful
	when you use a SWF player without tracing support.
      </para>
      
      <para>
	Test units are built by running <emphasis>make TestName-v#.swf</emphasis>.
	This will use TestName.as as source and the value of # as target version.
	Allowed target version are from 5 to 8 (inclusive).
      </para>
      
      <para>
	Note that if you get a syntax error from the compiler, the line
	number will refer to the pre-processed file. This file is called
	<emphasis>TestName.as.pp</emphasis> or <emphasis>TestName-v#.swf.frame#.pp</emphasis>
	(depending on Ming version) and it's not thrown away by
	<emphasis>makeswf</emphasis> to make debugging easier.
      </para>

      <para>
	Sometimes an expression is only supported by a specific SWF
	version, or it's evaluated differently by different SWF versions.
	For this purpose the framework provides an OUTPUT_VERSION macro
	that you can use to switch code based on output version. For example:

	<programlisting>

	  #if OUTPUT_VERSION &gt;= 7
	  check(_root.getSWFVersion == OUTPUT_VERSION);
	  #endif
	  
	</programlisting>
      </para>
    </sect2>

    <sect2 id="writemingtests">
      <title>Writing Ming-based self-contained SWF tests</title>

      <para>
	Ming-based test cases are located in testsuite/misc-ming.all
	and contain a test generator and a test runner.
	The test generator (usually a C program) is used to produce the SWF 
        file, while the test runner (a C++ program) will run it using a 
 	MovieTester class.
	Note that only the test generator needs Ming, not the test
	runner, so if Ming isn't installed on the user's host,
	the test cases can still be run as long as SWF has been distributed.
      </para>
      
      <para>
	Producing tests using Ming has the advantage that you can easily see
	and modify the full source code for the SWF movie, and you can use
	some <link linkend="ming_testgenerator_facilities">facilities</link>
	provided by the &app; testing framework to easily run tests.
      </para>

      <para>
	For generic Ming API documentation, see <ulink type="http"
	url="http://www.libming.org/">http://www.libming.org</ulink>. 
      </para>

      <sect3 id="ming_testgenerator_facilities">
      <title>Using Ming-based test generators facilities</title>

      <para>
	Ming-based test generator facilities, which might be moved into
	a loadable SWF in the future, can be currently used by your test
	generator by including the ming_utils.h file and calling the
	appropriate functions.
      </para>

      <para>
	The most useful facility provided for Ming-based SWF test generators
	is a Dejagnu-like TestState ActionScript class.
	In order to use this facility you must call 'add_dejagnu_functions()'
	right after Movie creation.
	The function takes an SWFMovie object and some parameters specifying
	depth and location of the "visual" trace textfield; it instantiates
	a global 'TestState' ActionScript object to keep track of test's state.
      </para>

      <para>
        You will <emphasis>not</emphasis> need to directly invoke the
	TestState object created by the 'add_dejagnu_functions()' routine,
	rather you will be using C macros hiding its complexity:
	
	<programlisting>

	check(SWFMovie mo, const char* expr)

		Evaluate an ActionScript expression.

	xcheck(SWFMovie mo, const char* expr)

		Evaluate an ActionScript expression.
		A failure is expected
		(for cases where the call exposes a known bug).

	check_equals(SWFMovie mo, const char* obtained, const char* expected)

		Evaluate an ActionScript expression against an expected output.

	xcheck_equals(SWFMovie mo, const char* obtained, const char* expected)

		Evaluate an ActionScript expression against an expected output.
		A failure is expected (for cases where the call exposes a known bug).

	print_tests_summary(SWFMovie mo)

                This will print a summary of tests run, and should be
		called as the last step in your SWF generator.
	</programlisting>
	
      </para>
      
      <para>
	Test cases generated using Ming and the provided
	<link linkend="ming_testgenerator_facilities">facilities</link>
	will be self-contained, which means they can be used as tests
	by simply running them with whatever Player you might have.
	Any 'check' or 'check_equals' result will be both traced and
	printed in a textfield. You can use 'gprocessor -v' to have
	&app; use them as tests.
      </para>
      
      <para>
	See section <link linkend="writing_test_runners">Writing Test Runners</link>
	for information about writing SWF test runners.
      </para>
      </sect3>
    </sect2>
    
    <sect2 id="writing_dejagnu_so_tests">
      <title>Writing self-contained SWF tests with other compilers</title>
      
      <para>
	If you want/need to use a different compiler for your test cases (there's
	plenty of open source tools for generating SWF out there), you can still
	make use of a loadable SWF utility provided as part of the &app; testsuite
	to let your test consistent with the rest of the suite.
      </para>
      
      <para>
	The loadable module is called <emphasis>Dejagnu.swf</emphasis> and is built during
	<emphasis>make check</emphasis> under testsuite/misc-ming.all. In order to use it
	you will need to load it into your SWF. We currently load it with an IMPORT
	tag for our ActionScript based test cases, but you can probably also use
	loadMovie or whatever works in the target SWF you're generating. Just make
	sure that the module is initialized before using it. You can check this by
	inspecting the <emphasis>dejagnu_module_initialized</emphasis> variable, which will
	be set to 'true' when all initialization actions contained in the
	<emphasis>Dejagnu.swf</emphasis> file are executed. 
      </para>
      
      <para>
	Once the module is loaded you will be able to invoke the following functions,
	all registered against the <emphasis>_root</emphasis> sprite (effects of <emphasis>_lockroot</emphasis>
	untested):
	<programlisting>
	  
	  check(expression, [message]);
	  
	  Evaluate the expression.
	  Trace result (PASSED: expression / FAILED: expression).
	  If fails, *visually* trace the failure.
	  If second argument is given, it will be used instead of
	  'expression' for printing results.
	  
	  check_equals(obtained, expected)
	  
	  Evaluate an expression against an expected output.
	  Trace result (PASSED: obtained == expected / FAILED: expected X, obtained Y)
	  If fails, *visually* trace the failure.
	  
	  xcheck(expression, [message]);
	  
	  Evaluate the expression.
	  Trace result (XPASSED: expression / XFAILED: expression).
	  If fails, *visually* trace the failure.
	  If second argument is given, it will be used instead of
	  'expression' for printing results.
	  
	  xcheck_equals(obtained, expected)
	  
	  Evaluate an expression against an expected output.
	  Trace result (XPASSED: obtained == expected / XFAILED: expected X, obtained Y)
	  If fails, *visually* trace the failure.
	  
	  note(string)
	  
	  Print string, both as debugging and *visual* trace.
	  
	  totals()
	  
	  Print a summary of tests run, both as debugging and *visual* traces.
	  
	</programlisting>
      </para>
      
      <para>
	Visual traces are lines of text pushed to a textarea defined
	by the <emphasis>Dejagnu.swf</emphasis> module. The textarea is
	initially placed at <emphasis>0, 50</emphasis> and is
	<emphasis>600x800</emphasis> in size. You can resize/move the clip
	after loading it. Also, you can completely make the clip
	invisible if that bothers you. The important thing is the
	<emphasis>debugging</emphasis> trace (call to the trace
	function). The latter will be used by the testing framework. 
      </para>
      
      <para>
	See section <link linkend="writing_test_runners">Writing Test Runners</link>
	for information about writing a test runners for your self-contained tests.
      </para>
      
    </sect2>
    
    <sect2 id="writing_test_runners">
      <title>Writing Test Runners</title>
      
      <para>
	Test runners are executables that run one or more tests,
	writing results in Dejagnu form to standard output.
      </para>
      
      <para>
	The Dejagnu form uses a standard set of labels when printing test 
	results.  These are:
	<informaltable frame="all">
	  <?dbhtml table-width="75%" ?>
	  <tgroup cols="2">
	    <thead>
	      <row>
		<entry valign="top">
		  <para>Label</para>
		</entry>
		<entry valign="top">
		  <para>Meaning</para>
		</entry>
	      </row>
	    </thead>
	    <tbody>
	      <row>
		<entry valign="top" align="left">
		  <para>PASSED</para>
		</entry>
		<entry valign="top" align="left">
		  <para>The test succeeded.</para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>FAILED</para>
		</entry>
		<entry valign="top" align="left">
		  <para>The test failed.</para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>XPASSED</para>
		</entry>
		<entry valign="top" align="left">
		  <para>The test succeeded, but was expected to fail.</para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>XFAILED</para>
		</entry>
		<entry valign="top" align="left">
		  <para>The test failed, and was expected to fail.</para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>UNRESOLVED</para>
		</entry>
		<entry valign="top" align="left">
		  <para>The results of the test could not be automatically 
		  parsed.</para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>UNTESTED</para>
		</entry>
		<entry valign="top" align="left">
		  <para>This test case is not complete.</para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>UNSUPPORTED</para>
		</entry>
		<entry valign="top" align="left">
		  <para>The test case relies on a conditional feature which 
		  is not present in your environment.</para>
		</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</informaltable>
      </para>
      
      <para>
	The following labels may also appear:
	<informaltable frame="all">
	  <?dbhtml table-width="75%" ?>
	  <tgroup cols="2">
	    <thead>
	      <row>
		<entry valign="top">
		  <para>Label</para>
		</entry>
		<entry valign="top">
		  <para>Meaning</para>
		</entry>
	      </row>
	    </thead>
	    <tbody>
	      <row>
		<entry valign="top" align="left">
		  <para>ERROR</para>
		</entry>
		<entry valign="top" align="left">
		  <para>There was a serious error in running the test. </para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>WARNING</para>
		</entry>
		<entry valign="top" align="left">
		  <para>There may have been a problem with running the
		  test.</para>
		</entry>
	      </row>
	      <row>
		<entry valign="top" align="left">
		  <para>NOTE</para>
		</entry>
		<entry valign="top" align="left">
		  <para>There was some additional information given about
		  the test.</para>
		</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</informaltable>
      </para>
      
      <sect3 id="generic_test_runner">
	<title>Using the generic test runner for self-contained SWF tests</title>
	
	<para>
	  The simplest test runner is one that simply invokes &app;
	  in verbose mode against a self-contained SWF test movie.
	  Self-contained SWF test movies are the ones that print
	  the PASSED/FAILED etc. lines using ActionScript (traces).
	  By invoking &app; in verbose mode this movie will behave
	  as a compliant "Test Runner".
	</para>
	
	<para>
	  A generator for simple test runners can be found in
	  <emphasis>testsuite/generic-testrunner.sh</emphasis>.
	  The script can be invoked by passing it <emphasis>$(top_builddir)</emphasis>
	  as the first argument and the name of the SWF file (without the path)
	  as the second argument. This will create a specific runner for your
	  test in the current build directory.
	  A simple Makefile.am rule for doing this follows:
	  <programlisting>
	    MyTest-Runner: $(srcdir)/../generic-testrunner.sh MyTest.swf
	    sh $(srcdir)/../generic-testrunner.sh $(top_builddir) MyTest.swf > $@
	    chmod +x $@
	  </programlisting>
	</para>
	
	<para>
	  By default, the generated test runner will play the movie up to the
	  last frame. If you want the movie to be played more then once (maybe
	  because you're exactly testing loop features) you can use the -r switch
	  to the generic-testrunner.sh call. The following will create a runner
	  playing the movie twice:
	  <programlisting>
	    MyTest-Runner: $(srcdir)/../generic-testrunner.sh MyTest.swf
	    sh $(srcdir)/../generic-testrunner.sh -r2 $(top_builddir) MyTest.swf > $@
	    chmod +x $@
	  </programlisting>
	</para>
	
	<para>
	  In case your test movie stops before the last frame, or you want to control the
	  exact number of times to call the frame advancement routine, you can use the 
	  -f switch to control that.
	  <programlisting>
	    MyTest-Runner: $(srcdir)/../generic-testrunner.sh MyTest.swf
	    sh $(srcdir)/../generic-testrunner.sh -f10 $(top_builddir) MyTest.swf > $@
	    chmod +x $@
	  </programlisting>
	  When both -f and -r are given, the first exit condition reached will take effect.
	</para>
	
      </sect3>
      
      <sect3 id="writing_movie_testers">
	<title>Writing Movie testers</title>
	
	<para>
	  There are some parts of &app; that can NOT be tested
	  by only using ActionScript tests. Examples include: frame
	  advancements, actual actions execution, gui events and so on.
	</para>
	
	<para>
	  In this case you might want to use the MovieTester class to
	  implement a C++ test runner. Be aware that you can <emphasis>mix</emphasis> tests in
	  the MovieTester-based class with <emphasis>self-contained</emphasis>
	  tests in the SWF file as long as you activate verbosity for
	  the debug logfile. This is done, for example, for the
	  DefineEditTextVariableNameTest.swf file. The corresponding
	  test runner (DefineEditTextVariableNameTest-Runner) is a C++
	  runner based on MovieTester class. If you run the runner you
	  see two kinds of test results: the ones coming from the ActionScript
	  engine, and the ones coming from the test runner. You can
	  distinguish between the two because the former contains an additional
	  timestamp and the latter does not. Also, you'll see two final
	  summaries for the two test sets. The 'make check' rule, which uses
	  the testsuite/simple.exp output parser as its work-horse, will
	  count test results from both test sets.
	</para>
	
	
	<para>
	  Movie testers are executables which load an SWF, generate events
	  (both user or system) on it, and check its state using
	  a standard interface.
	</para>
	
	<para>
	  To help this process a MovieTester class is defined in the
	  testsuite/MovieTester.{h,cpp} files; see Doxygen documentation
	  for more information.
	</para>
	
	<para>
	  Note that you do NOT need access to the SWF source code in order
	  to implement a Movie tester for it.  Some knowledge about the 
	  expected behavior suffices.
	</para>
      </sect3>
    </sect2>
  </sect1>
  
  &newasclass;
    
</chapter>

