<commit_before>Creating test libraries
-----------------------

Robot Framework's actual testing capabilities are provided by test
libraries. There are many existing libraries, some of which are even
bundled with the core framework, but there is still often a need to
create new ones. This task is not too complicated because, as this
chapter illustrates, Robot Framework's library API is simple
and straightforward.

.. contents::
   :depth: 2 
   :local: 


Introduction
~~~~~~~~~~~~

Supported programming languages
'''''''''''''''''''''''''''''''

Robot Framework itself is written with Python_ and naturally test
libraries extending it can be implemented using the same
language. When running the framework on Jython_, libraries can also be
implemented using Java_. Pure Python code works both on Python and
Jython, assuming that it does not use syntax or modules that are not
available on Jython. When using Python, it is also possible to
implement libraries with C using `Python C API`__, although it is
often easier to interact with C code from Python libraries using
ctypes__ module.

Libraries implemented using these natively supported languages can
also act as wrappers to functionality implemented using other
programming languages. A good example of this approach is the `Remote
library`_, and another widely used approaches is running external
scripts or tools as separate processes.

.. tip:: `Python Tutorial for Robot Framework Test Library Developers`__
         covers enough of Python language to get started writing test
         libraries using it. It also contains a simple example library
         and test cases that you can execute and otherwise investigate 
         on your machine. 

__ http://docs.python.org/c-api/index.html
__ http://docs.python.org/library/ctypes.html
__ http://code.google.com/p/robotframework/wiki/PythonTutorial

Different test library APIs
'''''''''''''''''''''''''''

Robot Framework has three different test library APIs. 

Static API 

  The simplest approach is having a module (in Python) or a class
  (in Python or Java) with methods the names of which map more or less
  directly to `keyword names`_. Keywords also take the same `arguments`__ as
  the code implementing them.  Keywords `report failures`__ with
  exceptions, `log`__ by writing to standard output and can `return
  values`__ using the :code:`return` statement.

Dynamic API

  Dynamic libraries are classes that implement a method to get the names
  of the keywords they implement, and another method to execute a named 
  keyword with given arguments. The names of the keywords to implement, as
  well as how they are executed, can be determined dynamically at
  runtime, but reporting the status, logging and returning values is done
  similarly as in the static API.

Hybrid API

  This is a hybrid between the static and the dynamic API. Libraries are
  classes with a method telling what keywords they implement, but
  those keywords must be available directly. Everything else except
  discovering what keywords are implemented is similar as in the
  static API.
  
All these APIs are described in this chapter. Everything is based on
how the static API works, so its functions are discussed first. How
the `dynamic library API`_ and the `hybrid library API`_ differ from it
is then discussed in sections of their own.

The examples in this chapter are mainly about using Python, but they
should be easy to understand also for Java-only developers. In those
few cases where APIs have differences, both usages are explained with
adequate examples.

__ `Keyword arguments`_
__ `Reporting keyword status`_
__ `Logging information`_
__ `Returning values`_


Creating test library class or module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test libraries can be implemented as Python modules or Python or Java classes. 
In Robot Framework 2.0.1 and earlier, it is possible to use only classic
classes as test libraries. Both classic and new style classes are 
supported from 2.0.2 onwards.

Test library names
''''''''''''''''''

The name of a test library that is used when a library is imported is
the same as the name of the module or class implementing it. For
example, if you have a Python module :code:`MyLibrary` (that is, the
file :path:`MyLibrary.py`), it will create a library with a name
:name:`MyLibrary`. Similarly, a Java class :code:`YourLibrary`, when
it is not in any package, creates a library with exactly that name.

Python classes are always inside a module. If the name of a class
implementing a library is the same as the name of the module, Robot
Framework allows dropping the module name when importing the
library. For example, the class :code:`MyLib` in the :path:`MyLib.py`
file can be used as a library with the name :name:`MyLib`. If the
module name and class name are different, libraries must be taken into
use using both module and class names, such as
:name:`mymodule.MyLibrary`.

Java classes in a non-default package must be taken into use with the
full name. For example, the class :code:`MyLib` in the
:code:`com.mycompany.myproject` package must be imported with the name
:name:`com.mycompany.myproject.MyLib`.

.. Tip:: If the library name is really long, for example when the Java
         package name is long, it is recommended to give the library a
         simpler alias by using the `WITH NAME syntax`_.

Providing arguments to test libraries
'''''''''''''''''''''''''''''''''''''

All test libraries implemented as classes can take arguments. These
arguments are specified in the Setting table after the library name,
and when Robot Framework creates an instance of the imported library,
it passes them to its constructor. Libraries implemented as a module
cannot take any arguments, so trying to use those results in an error.

The number of arguments needed by the library is the same
as the number of arguments accepted by the library's
constructor. The default values and variable number of arguments work
similarly as with `keyword arguments`_, with the exception that there
is no variable argument support for Java libraries. Arguments passed
to the library, as well as the library name itself, can be specified
using variables, so it is possible to alter them, for example, from the command
line.

.. table:: Importing a test library with arguments
   :class: example

   =========  ===========  =========  =======
    Setting      Value       Value     Value
   =========  ===========  =========  =======
   Library    MyLibrary    10.0.0.1   8080
   Library    AnotherLib   ${VAR}     \
   =========  ===========  =========  =======

Example implementations, first one in Python and second in Java, for
the libraries used in the above example:

.. sourcecode:: python

  from example import Connection

  class MyLibrary:

      def __init__(self, host, port=80):
          self._conn = Connection(host, int(port))

      def send_message(self, message):
          self._conn.send(message)

.. sourcecode:: java

   public class AnotherLib {

       private String setting = null;

       public AnotherLib(String setting) {
           setting = setting;
       }

       public void doSomething() {
           if setting.equals("42") {
               // do something ...
           }
       }
   }

Test library scope
''''''''''''''''''

Libraries implemented as classes can have an internal state, which can
be altered by keywords and with arguments to the constructor of the
library. Because the state can affect how keywords actually behave, it
is important to make sure that changes in one test case do not
accidentally affect other test cases. This kind of dependencies may
create hard-to-debug problems, for example, when new test cases are
added and they use the library inconsistently.

Robot Framework attempts to keep test cases independent from each
other: by default, it creates new instances of test libraries for
every test case. However, this behavior is not always desirable,
because sometimes test cases should be able to share a common
state. Additionally, all libraries do not have a state and creating
new instances of them is simply not needed.

Test libraries can control when new libraries are created with a
class attribute :code:`ROBOT_LIBRARY_SCOPE` . This attribute must be
a string and it can have the following three values:

`TEST CASE`:code:
  A new instance is created for every test case. A possible suite setup
  and suite teardown share yet another instance. This is the default.

`TEST SUITE`:code:
  A new instance is created for every test suite. The lowest-level test
  suites, created from test case files and containing test cases, have
  instances of their own, and higher-level suites all get their own instances
  for their possible setups and teardowns.

`GLOBAL`:code: 
  Only one instance is created during the whole test execution and it
  is shared by all test cases and test suites. Libraries created from
  modules are always global.

When the :code:`TEST SUITE` or :code:`GLOBAL` scopes are used with test
libraries that have a state, it is recommended that libraries have some
special keyword for cleaning up the state. This keyword can then be
used, for example, in a suite setup or teardown to ensure that test
cases in the next test suites can start from a known state. For example,
:name:`SeleniumLibrary` uses the :code:`GLOBAL` scope to enable
using the same browser in different test cases without having to
reopen it, and it also has the :name:`Close All Browsers` keyword for
easily closing all open browsers.

Example Python library using the :code:`TEST SUITE` scope:

.. sourcecode:: python

    class ExampleLibrary:

        ROBOT_LIBRARY_SCOPE = 'TEST SUITE'

        def __init__(self):
            self._counter = 0
  
        def count(self):
            self._counter += 1
            print self._counter

        def clear_counter(self):
            self._counter = 0

Example Java library using the :code:`GLOBAL` scope:

.. sourcecode:: java

    public class ExampleLibrary {

        public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";

        private int counter = 0;

        public void count() {
            counter += 1;
            System.out.println(counter);
        }

        public void clearCounter() {
            counter = 0;
        }
    }

Specifying library version
''''''''''''''''''''''''''

When a test library is taken into use, Robot Framework tries to
determine its version. This information is then written into the syslog_
to provide debugging information. Library documentation tool
`libdoc.py`_ also writes this information into the keyword
documentations it generates.

Version information is read from attribute
:code:`ROBOT_LIBRARY_VERSION`, similarly as `test library scope`_ is
read from :code:`ROBOT_LIBRARY_SCOPE`. If
:code:`ROBOT_LIBRARY_VERSION` does not exist, information is tried to
be read from :code:`__version__` attribute. These attributes must be a
class or module attributes, depending whether the library is
implemented as a class or a module.  For Java libraries, the version
attribute must be declared as :code:`static final`.

An example Python module using :code:`__version__`:

.. sourcecode:: python

    __version__ = '0.1'

    def keyword():
        pass

A Java class using :code:`ROBOT_LIBRARY_VERSION`:

.. sourcecode:: java

    public class VersionExample {
        
        public static final String ROBOT_LIBRARY_VERSION = "1.0.2";
        
        public void keyword() {
        }
    }


Creating static keywords
~~~~~~~~~~~~~~~~~~~~~~~~

Keyword names
'''''''''''''

When the static library API is used, Robot Framework uses reflection
to find out what methods the library implements. With `dynamic library
API`_ and `hybrid library API`_, keyword names are got from the
library directly. Naturally, Robot Framework can see only the public
methods and it also excludes all methods starting with an
underscore. With Java libraries, also methods that are implemented in
:code:`java.lang.Object` and not overridden are ignored.

Keyword names used in the test data are compared with method names to
find the method implementing these keywords. Name comparison is
case-insensitive, and also spaces and underscores are ignored. For
example, the method :code:`hello` maps to the keyword name
:name:`Hello`, :name:`hello` or even :name:`h e l l o`. Similarly both the
:code:`do_nothing` and :code:`doNothing` methods can be used as the
:name:`Do Nothing` keyword in the test data.

Example Python library implemented as a module in the :path:`MyLibrary.py` file:

.. sourcecode:: python

  def hello(name):
      print "Hello, %s!" % name

  def do_nothing():
      pass

Example Java library implemented as a class in the :path:`MyLibrary.java` file:

.. sourcecode:: java

  public class MyLibrary {

      public void hello(String name) {
          System.out.println("Hello, " + name + "!");
      }

      public void doNothing() { 
      }

  }

The example below illustrates how the example libraries above can be
used. If you want to try this yourself, make sure that the library is
in the `library search path`_. Note that in the subsequent examples all
boilerplates, such as taking a library into use and creating a test
case, is excluded.

.. table:: Using simple example library
   :class: example  

   =========  ===========  =======  =======
    Setting      Value      Value    Value
   =========  ===========  =======  =======
   Library     MyLibrary   \        \
   =========  ===========  =======  =======

.. table::
   :class: example

   ===========  ===========  ============  ============
    Test Case     Action       Argument      Argument
   ===========  ===========  ============  ============
   My Test      Do Nothing   \             \
   \            Hello        world         \
   ===========  ===========  ============  ============

Keyword arguments
'''''''''''''''''

With a static and hybrid API, the information on how many arguments a
keyword needs is got directly from the method that implements it.
Libraries using the `dynamic library API`_ have other means for getting
this information, so this section is not relevant to them.

The most common and also simplest situation is when a keyword needs an
exact number of arguments. In this case, both the Python and Java methods
simply take exactly those arguments. For example, a method implementing a
keyword with no arguments takes no arguments either, a method
implementing a keyword with one argument also takes one argument, and
so on.

Example Python keywords taking different numbers of arguments:

.. sourcecode:: python

  def no_arguments():
      print "Keyword got no arguments"

  def one_argument(arg):
      print "Keyword got one argument '%s'" % arg

  def multiple_arguments(a1, a2, a3):
      print "Keyword got three arguments '%s', '%s' and '%s'" % (a1, a2, a3)

Default values to keywords
''''''''''''''''''''''''''

It is often useful that some of the arguments that a keyword uses have
default values. Python and Java have different syntax for handling default
values to methods, and the natural syntax of these languages can be
used when creating test libraries for Robot Framework.

Default values with Python
``````````````````````````
In Python a method has always exactly one implementation and possible
default values are specified in the method signature. The syntax,
which is familiar to all Python programmers, is illustrated below:

.. sourcecode:: python

   def one_default(arg='default'):
       print "Argument has value '%s'" % arg

   def multiple_defaults(arg1, arg2='default 1', arg3='default 2'):
       print "Got arguments %s, %s and %s" % (arg1, arg2, arg3)

The first example keyword above can be used either with zero or one
arguments. If no arguments are given, :code:`arg` gets the value
:code:`default`. If there is one argument, :code:`arg` gets that value,
and calling the keyword with any other number of arguments fails. In the
second example, one argument is always required, but the second and
the third one have default values, so it is possible to use the keyword
with one to three arguments.

.. table:: Using keywords with variable number of arguments
   :class: example

   ===========  ==================  =============  ============  =============
    Test Case         Action          Argument       Argument       Argument 
   ===========  ==================  =============  ============  =============
   Defaults     One Default         \              \             \
   \            One Default         argument       \             \
   \            Multiple Defaults   required arg   \             \
   \            Multiple Defaults   required arg   optional      \
   \            Multiple Defaults   required arg   optional 1    optional 2
   ===========  ==================  =============  ============  =============

Default values with Java
````````````````````````
In Java one method can have several implementations with different
signatures. Robot Framework regards all these implementations as one
keyword, which can be used with different arguments. This syntax can
thus be used to provide support for the default values. This is
illustrated by the example below, which is functionally identical to
the earlier Python example:

.. sourcecode:: java
  
   public void oneDefault(String arg) {
       System.out.println("Argument has value '" + arg "'");
   }

   public void oneDefault() {
       oneDefault("default");
   }

   public void multipleDefaults(String arg1, String arg2, String arg3) {
       System.out.println("Got arguments " + arg1 + ", " + arg2 + " and " + arg3);
   }

   public void multipleDefaults(String arg1, String arg2) {
       multipleDefaults(arg1, arg2, "default 2");
   }

   public void multipleDefaults(String arg1) {
       multipleDefaults(arg1, "default 1");
   }

Variable number of arguments
''''''''''''''''''''''''''''

Robot Framework supports also keywords that take any number of
arguments. Similarly as with the default values, the actual syntax to use
in test libraries is different in Python and Java.

Variable number of arguments with Python
````````````````````````````````````````
Python itself has a good support for methods accepting any
number of arguments. The same syntax works in libraries and, as
the examples below show, it can also be combined with other ways of
specifying arguments:

.. sourcecode:: python

  def any_arguments(*args):
      print "Got arguments:"
      for arg in args:
          print arg

  def one_required(required, *others):
      print "Required: %s\nOthers:" % required
      for arg in others:
          print arg

  def also_defaults(req, def1="default 1", def2="default 2", *rest):
      print req, def1, def2, rest

.. table:: Using keywords with a variable number of arguments
   :class: example

   ===========  ==============  =============  ============  ==============
    Test Case       Action         Argument      Argument       Argument 
   ===========  ==============  =============  ============  ==============
   Varargs      Any Arguments   \              \             \
   \            Any Arguments   argument       \             \
   \            Any Arguments   arg 1          arg 2         arg 2
   \            ...             arg 4          arg 5         \
   \            One Required    required arg   \             \
   \            One Required    required arg   another arg   yet another
   \            Also Defaults   required       \             \
   \            Also Defaults   required       these two     have defaults 
   \            Also Defaults   1              2             3
   \            ...             4              5             6
   ===========  ==============  =============  ============  ==============

Variable number of arguments with Java
``````````````````````````````````````
In Java, there is no syntax for a variable number of arguments, but Robot
Framework has its own support for them. If the last argument in a keyword
signature is an array, all leftover arguments are packed into
it. This also works, if the keyword is used with one argument less than
the actual number of arguments in the signature - in this case the
array at the end will be empty. 

This system has one limitation: it only works if the method has one
signature. Thus it is not possible to have a Java keyword that has
both the default values and a variable number of arguments. Of course,
having the required values with a variable number of arguments is
possible, as the examples below illustrate:

.. sourcecode:: java

  public void anyArguments(String[] args) {
      System.out.println("Got arguments:");
      for (int i; i < args.length; i++) {
          System.out.println(args[i]);
      }
  }

  public void oneRequired(String required, String[] others) {
      System.out.println("Required: " + required + "\nOthers:");
      for (int i; i < others.length; i++) {
          System.out.println(others[i]);
      }
  }

Argument types
''''''''''''''

Normally keyword arguments come to Robot Framework as strings. If
keywords require some other types, it is possible to either use
variables_ or convert strings to required types inside keywords. With
`Java keywords`__ base types are also coerced automatically.

__ `Argument types with Java`_

Argument types with Python
``````````````````````````
Because arguments in Python do not have any type information, there is
no possibility to automatically convert strings to other types when
using Python libraries. Calling a Python method implementing a keyword
with a correct number of arguments always succeeds, but the execution
fails later if the arguments are incompatible. Luckily with Python it
is simple to convert arguments to suitable types inside keywords:

.. sourcecode:: python

  def connect_to_host(address, port=25):
      port = int(port)
      # ...

Argument types with Java
````````````````````````
Arguments to Java methods have types, and starting from Robot
Framework 2.1 all the base types are handled automatically. This
means that arguments that are normal strings in the test data are
coerced to correct type at runtime. The types that can be coerced
are:

- integer types (:code:`byte`, :code:`short`, :code:`int`, :code:`long`)
- floating point types (:code:`float` and :code:`double`)
- the :code:`boolean` type
- object versions of the above types e.g. :code:`java.lang.Integer`

The coercion is done for arguments that have the same or compatible
type across all the signatures of the keyword method. In the following
example, the conversion can be done for keywords :code:`doubleArgument`
and :code:`compatibleTypes`, but not for :code:`conflictingTypes`.

.. sourcecode:: java
  
   public void doubleArgument(double arg) {}

   public void compatibleTypes(String arg1, Integer arg2) {}
   public void compatibleTypes(String arg2, Integer arg2, Boolean arg3) {}

   public void conflictingTypes(String arg1, int arg2) {}
   public void conflictingTypes(int arg1, String arg2) {}

The coercion works with the numeric types if the test data has a
string containing a number, and with the boolean type the data must
contain either string :code:`true` or :code:`false`. Coercion is only
done if the original value was a string from the test data, but it is
of course still possible to use variables containing correct types with
these keywords. With keywords having conflicting signatures using
variables is the only option.

.. table:: Using automatic type coercion
   :class: example

   ===========  =================  =============  ==========  =====================
    Test Case         Action          Argument     Argument        Argument 
   ===========  =================  =============  ==========  =====================
   Coercion     Double Argument    3.14
   \            Double Argument    2e16                       # scientific notation
   \            Compatible Types   Hello, world!  1234          
   \            Compatible Types   Hi again!      -10         true
   \
   No Coercion  Double Argument    ${3.14}                         
   \            Conflicting Types  1              ${2}        # must use variables
   \            Conflicting Types  ${1}           2              
   ===========  =================  =============  ==========  =====================


Communicating with Robot Framework
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After a method implementing a keyword is called, it can use any
mechanism to communicate with the system under test. It can then also
send messages to Robot Framework's log file, return information that
can be saved to variables and, most importantly, report if the
keyword passed or not. 

Reporting keyword status
''''''''''''''''''''''''

Reporting keyword status is done simply using exceptions. If an executed
method raises an exception, the keyword status is :msg:`FAIL`, and if it
returns normally, the status is :msg:`PASS`.

The error message shown in logs, reports and the console is created
from the exception type and its message. With generic exceptions (for
example, :code:`AssertionError`, :code:`Exception`, and
:code:`RuntimeError`), only the exception message is used, and with
others, the message is created in the format :msg:`ExceptionType:
Actual message`. In both cases, it is important for the users that the
exception message is as informative as possible.

If the error message is longer than 40 lines, it will be automatically
cut from the middle to prevent reports from getting too long and
difficult to read. The full error message is always shown in the log
message of the failed keyword.

The traceback of the exception is also logged using :msg:`DEBUG` `log level`_.
These messages are not visible in log files by default because they are very
rarely interesting for normal users. When developing libraries, it is often a
good idea to run tests using :cli:`--loglevel DEBUG`.

Stopping test execution
'''''''''''''''''''''''

Starting from Robot Framework 2.5 it is possible to fail a test case so that
`the whole test execution is stopped`__. This is done simply by having a special
:code:`ROBOT_EXIT_ON_FAILURE` attribute with :code:`True` value set on the 
exception raised from the keyword. This is illustrated in the examples below.

Python:

.. sourcecode:: python

    class MyFatalError(RuntimeError):
        ROBOT_EXIT_ON_FAILURE = True

Java:

.. sourcecode:: java

    public class MyFatalError extends RuntimeException {
        public static final boolean ROBOT_EXIT_ON_FAILURE = true;
    } 

__ `Exit on failure`_

Logging information
'''''''''''''''''''

Exception messages are not the only way to give information to the
users. In addition to that, methods can also send messages to `log
files`_ simply by writing to standard output (stdout) or standard
error (stderr), and they can even use different `log levels`_.

By default, everything written by a method into standard output is written
to the log file as a single entry with the log level
:msg:`INFO`. Messages written into standard error are handled similarly
otherwise, but they are echoed back to the original stderr after the
keyword execution has finished. It is thus possible to use stderr if you need
some messages to be visible on the console where tests are executed.

To use other log levels than :msg:`INFO`, or to create several
messages, specify the log level explicitly by embedding the level into
the message in the format :msg:`*LEVEL* Actual log message`, where
:msg:`*LEVEL*` must be in the beginning of a line and :msg:`LEVEL` is
one of the available logging levels :msg:`TRACE`, :msg:`DEBUG`,
:msg:`INFO`, :msg:`WARN` and :msg:`HTML`.

Warnings
````````
Starting from Robot Framework 2.1 messages with :msg:`WARN` level are
automatically written into `the console and into separate Test Execution
Errors section`__ in log files. This makes warnings more visible than
other messages and allows using them for reporting important but 
non-critical problems to users.
<commit_msg>Added continue on failure<commit_after>Creating test libraries
-----------------------

Robot Framework's actual testing capabilities are provided by test
libraries. There are many existing libraries, some of which are even
bundled with the core framework, but there is still often a need to
create new ones. This task is not too complicated because, as this
chapter illustrates, Robot Framework's library API is simple
and straightforward.

.. contents::
   :depth: 2 
   :local: 


Introduction
~~~~~~~~~~~~

Supported programming languages
'''''''''''''''''''''''''''''''

Robot Framework itself is written with Python_ and naturally test
libraries extending it can be implemented using the same
language. When running the framework on Jython_, libraries can also be
implemented using Java_. Pure Python code works both on Python and
Jython, assuming that it does not use syntax or modules that are not
available on Jython. When using Python, it is also possible to
implement libraries with C using `Python C API`__, although it is
often easier to interact with C code from Python libraries using
ctypes__ module.

Libraries implemented using these natively supported languages can
also act as wrappers to functionality implemented using other
programming languages. A good example of this approach is the `Remote
library`_, and another widely used approaches is running external
scripts or tools as separate processes.

.. tip:: `Python Tutorial for Robot Framework Test Library Developers`__
         covers enough of Python language to get started writing test
         libraries using it. It also contains a simple example library
         and test cases that you can execute and otherwise investigate 
         on your machine. 

__ http://docs.python.org/c-api/index.html
__ http://docs.python.org/library/ctypes.html
__ http://code.google.com/p/robotframework/wiki/PythonTutorial

Different test library APIs
'''''''''''''''''''''''''''

Robot Framework has three different test library APIs. 

Static API 

  The simplest approach is having a module (in Python) or a class
  (in Python or Java) with methods the names of which map more or less
  directly to `keyword names`_. Keywords also take the same `arguments`__ as
  the code implementing them.  Keywords `report failures`__ with
  exceptions, `log`__ by writing to standard output and can `return
  values`__ using the :code:`return` statement.

Dynamic API

  Dynamic libraries are classes that implement a method to get the names
  of the keywords they implement, and another method to execute a named 
  keyword with given arguments. The names of the keywords to implement, as
  well as how they are executed, can be determined dynamically at
  runtime, but reporting the status, logging and returning values is done
  similarly as in the static API.

Hybrid API

  This is a hybrid between the static and the dynamic API. Libraries are
  classes with a method telling what keywords they implement, but
  those keywords must be available directly. Everything else except
  discovering what keywords are implemented is similar as in the
  static API.
  
All these APIs are described in this chapter. Everything is based on
how the static API works, so its functions are discussed first. How
the `dynamic library API`_ and the `hybrid library API`_ differ from it
is then discussed in sections of their own.

The examples in this chapter are mainly about using Python, but they
should be easy to understand also for Java-only developers. In those
few cases where APIs have differences, both usages are explained with
adequate examples.

__ `Keyword arguments`_
__ `Reporting keyword status`_
__ `Logging information`_
__ `Returning values`_


Creating test library class or module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Test libraries can be implemented as Python modules or Python or Java classes. 
In Robot Framework 2.0.1 and earlier, it is possible to use only classic
classes as test libraries. Both classic and new style classes are 
supported from 2.0.2 onwards.

Test library names
''''''''''''''''''

The name of a test library that is used when a library is imported is
the same as the name of the module or class implementing it. For
example, if you have a Python module :code:`MyLibrary` (that is, the
file :path:`MyLibrary.py`), it will create a library with a name
:name:`MyLibrary`. Similarly, a Java class :code:`YourLibrary`, when
it is not in any package, creates a library with exactly that name.

Python classes are always inside a module. If the name of a class
implementing a library is the same as the name of the module, Robot
Framework allows dropping the module name when importing the
library. For example, the class :code:`MyLib` in the :path:`MyLib.py`
file can be used as a library with the name :name:`MyLib`. If the
module name and class name are different, libraries must be taken into
use using both module and class names, such as
:name:`mymodule.MyLibrary`.

Java classes in a non-default package must be taken into use with the
full name. For example, the class :code:`MyLib` in the
:code:`com.mycompany.myproject` package must be imported with the name
:name:`com.mycompany.myproject.MyLib`.

.. Tip:: If the library name is really long, for example when the Java
         package name is long, it is recommended to give the library a
         simpler alias by using the `WITH NAME syntax`_.

Providing arguments to test libraries
'''''''''''''''''''''''''''''''''''''

All test libraries implemented as classes can take arguments. These
arguments are specified in the Setting table after the library name,
and when Robot Framework creates an instance of the imported library,
it passes them to its constructor. Libraries implemented as a module
cannot take any arguments, so trying to use those results in an error.

The number of arguments needed by the library is the same
as the number of arguments accepted by the library's
constructor. The default values and variable number of arguments work
similarly as with `keyword arguments`_, with the exception that there
is no variable argument support for Java libraries. Arguments passed
to the library, as well as the library name itself, can be specified
using variables, so it is possible to alter them, for example, from the command
line.

.. table:: Importing a test library with arguments
   :class: example

   =========  ===========  =========  =======
    Setting      Value       Value     Value
   =========  ===========  =========  =======
   Library    MyLibrary    10.0.0.1   8080
   Library    AnotherLib   ${VAR}     \
   =========  ===========  =========  =======

Example implementations, first one in Python and second in Java, for
the libraries used in the above example:

.. sourcecode:: python

  from example import Connection

  class MyLibrary:

      def __init__(self, host, port=80):
          self._conn = Connection(host, int(port))

      def send_message(self, message):
          self._conn.send(message)

.. sourcecode:: java

   public class AnotherLib {

       private String setting = null;

       public AnotherLib(String setting) {
           setting = setting;
       }

       public void doSomething() {
           if setting.equals("42") {
               // do something ...
           }
       }
   }

Test library scope
''''''''''''''''''

Libraries implemented as classes can have an internal state, which can
be altered by keywords and with arguments to the constructor of the
library. Because the state can affect how keywords actually behave, it
is important to make sure that changes in one test case do not
accidentally affect other test cases. This kind of dependencies may
create hard-to-debug problems, for example, when new test cases are
added and they use the library inconsistently.

Robot Framework attempts to keep test cases independent from each
other: by default, it creates new instances of test libraries for
every test case. However, this behavior is not always desirable,
because sometimes test cases should be able to share a common
state. Additionally, all libraries do not have a state and creating
new instances of them is simply not needed.

Test libraries can control when new libraries are created with a
class attribute :code:`ROBOT_LIBRARY_SCOPE` . This attribute must be
a string and it can have the following three values:

`TEST CASE`:code:
  A new instance is created for every test case. A possible suite setup
  and suite teardown share yet another instance. This is the default.

`TEST SUITE`:code:
  A new instance is created for every test suite. The lowest-level test
  suites, created from test case files and containing test cases, have
  instances of their own, and higher-level suites all get their own instances
  for their possible setups and teardowns.

`GLOBAL`:code: 
  Only one instance is created during the whole test execution and it
  is shared by all test cases and test suites. Libraries created from
  modules are always global.

When the :code:`TEST SUITE` or :code:`GLOBAL` scopes are used with test
libraries that have a state, it is recommended that libraries have some
special keyword for cleaning up the state. This keyword can then be
used, for example, in a suite setup or teardown to ensure that test
cases in the next test suites can start from a known state. For example,
:name:`SeleniumLibrary` uses the :code:`GLOBAL` scope to enable
using the same browser in different test cases without having to
reopen it, and it also has the :name:`Close All Browsers` keyword for
easily closing all open browsers.

Example Python library using the :code:`TEST SUITE` scope:

.. sourcecode:: python

    class ExampleLibrary:

        ROBOT_LIBRARY_SCOPE = 'TEST SUITE'

        def __init__(self):
            self._counter = 0
  
        def count(self):
            self._counter += 1
            print self._counter

        def clear_counter(self):
            self._counter = 0

Example Java library using the :code:`GLOBAL` scope:

.. sourcecode:: java

    public class ExampleLibrary {

        public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";

        private int counter = 0;

        public void count() {
            counter += 1;
            System.out.println(counter);
        }

        public void clearCounter() {
            counter = 0;
        }
    }

Specifying library version
''''''''''''''''''''''''''

When a test library is taken into use, Robot Framework tries to
determine its version. This information is then written into the syslog_
to provide debugging information. Library documentation tool
`libdoc.py`_ also writes this information into the keyword
documentations it generates.

Version information is read from attribute
:code:`ROBOT_LIBRARY_VERSION`, similarly as `test library scope`_ is
read from :code:`ROBOT_LIBRARY_SCOPE`. If
:code:`ROBOT_LIBRARY_VERSION` does not exist, information is tried to
be read from :code:`__version__` attribute. These attributes must be a
class or module attributes, depending whether the library is
implemented as a class or a module.  For Java libraries, the version
attribute must be declared as :code:`static final`.

An example Python module using :code:`__version__`:

.. sourcecode:: python

    __version__ = '0.1'

    def keyword():
        pass

A Java class using :code:`ROBOT_LIBRARY_VERSION`:

.. sourcecode:: java

    public class VersionExample {
        
        public static final String ROBOT_LIBRARY_VERSION = "1.0.2";
        
        public void keyword() {
        }
    }


Creating static keywords
~~~~~~~~~~~~~~~~~~~~~~~~

Keyword names
'''''''''''''

When the static library API is used, Robot Framework uses reflection
to find out what methods the library implements. With `dynamic library
API`_ and `hybrid library API`_, keyword names are got from the
library directly. Naturally, Robot Framework can see only the public
methods and it also excludes all methods starting with an
underscore. With Java libraries, also methods that are implemented in
:code:`java.lang.Object` and not overridden are ignored.

Keyword names used in the test data are compared with method names to
find the method implementing these keywords. Name comparison is
case-insensitive, and also spaces and underscores are ignored. For
example, the method :code:`hello` maps to the keyword name
:name:`Hello`, :name:`hello` or even :name:`h e l l o`. Similarly both the
:code:`do_nothing` and :code:`doNothing` methods can be used as the
:name:`Do Nothing` keyword in the test data.

Example Python library implemented as a module in the :path:`MyLibrary.py` file:

.. sourcecode:: python

  def hello(name):
      print "Hello, %s!" % name

  def do_nothing():
      pass

Example Java library implemented as a class in the :path:`MyLibrary.java` file:

.. sourcecode:: java

  public class MyLibrary {

      public void hello(String name) {
          System.out.println("Hello, " + name + "!");
      }

      public void doNothing() { 
      }

  }

The example below illustrates how the example libraries above can be
used. If you want to try this yourself, make sure that the library is
in the `library search path`_. Note that in the subsequent examples all
boilerplates, such as taking a library into use and creating a test
case, is excluded.

.. table:: Using simple example library
   :class: example  

   =========  ===========  =======  =======
    Setting      Value      Value    Value
   =========  ===========  =======  =======
   Library     MyLibrary   \        \
   =========  ===========  =======  =======

.. table::
   :class: example

   ===========  ===========  ============  ============
    Test Case     Action       Argument      Argument
   ===========  ===========  ============  ============
   My Test      Do Nothing   \             \
   \            Hello        world         \
   ===========  ===========  ============  ============

Keyword arguments
'''''''''''''''''

With a static and hybrid API, the information on how many arguments a
keyword needs is got directly from the method that implements it.
Libraries using the `dynamic library API`_ have other means for getting
this information, so this section is not relevant to them.

The most common and also simplest situation is when a keyword needs an
exact number of arguments. In this case, both the Python and Java methods
simply take exactly those arguments. For example, a method implementing a
keyword with no arguments takes no arguments either, a method
implementing a keyword with one argument also takes one argument, and
so on.

Example Python keywords taking different numbers of arguments:

.. sourcecode:: python

  def no_arguments():
      print "Keyword got no arguments"

  def one_argument(arg):
      print "Keyword got one argument '%s'" % arg

  def multiple_arguments(a1, a2, a3):
      print "Keyword got three arguments '%s', '%s' and '%s'" % (a1, a2, a3)

Default values to keywords
''''''''''''''''''''''''''

It is often useful that some of the arguments that a keyword uses have
default values. Python and Java have different syntax for handling default
values to methods, and the natural syntax of these languages can be
used when creating test libraries for Robot Framework.

Default values with Python
``````````````````````````
In Python a method has always exactly one implementation and possible
default values are specified in the method signature. The syntax,
which is familiar to all Python programmers, is illustrated below:

.. sourcecode:: python

   def one_default(arg='default'):
       print "Argument has value '%s'" % arg

   def multiple_defaults(arg1, arg2='default 1', arg3='default 2'):
       print "Got arguments %s, %s and %s" % (arg1, arg2, arg3)

The first example keyword above can be used either with zero or one
arguments. If no arguments are given, :code:`arg` gets the value
:code:`default`. If there is one argument, :code:`arg` gets that value,
and calling the keyword with any other number of arguments fails. In the
second example, one argument is always required, but the second and
the third one have default values, so it is possible to use the keyword
with one to three arguments.

.. table:: Using keywords with variable number of arguments
   :class: example

   ===========  ==================  =============  ============  =============
    Test Case         Action          Argument       Argument       Argument 
   ===========  ==================  =============  ============  =============
   Defaults     One Default         \              \             \
   \            One Default         argument       \             \
   \            Multiple Defaults   required arg   \             \
   \            Multiple Defaults   required arg   optional      \
   \            Multiple Defaults   required arg   optional 1    optional 2
   ===========  ==================  =============  ============  =============

Default values with Java
````````````````````````
In Java one method can have several implementations with different
signatures. Robot Framework regards all these implementations as one
keyword, which can be used with different arguments. This syntax can
thus be used to provide support for the default values. This is
illustrated by the example below, which is functionally identical to
the earlier Python example:

.. sourcecode:: java
  
   public void oneDefault(String arg) {
       System.out.println("Argument has value '" + arg "'");
   }

   public void oneDefault() {
       oneDefault("default");
   }

   public void multipleDefaults(String arg1, String arg2, String arg3) {
       System.out.println("Got arguments " + arg1 + ", " + arg2 + " and " + arg3);
   }

   public void multipleDefaults(String arg1, String arg2) {
       multipleDefaults(arg1, arg2, "default 2");
   }

   public void multipleDefaults(String arg1) {
       multipleDefaults(arg1, "default 1");
   }

Variable number of arguments
''''''''''''''''''''''''''''

Robot Framework supports also keywords that take any number of
arguments. Similarly as with the default values, the actual syntax to use
in test libraries is different in Python and Java.

Variable number of arguments with Python
````````````````````````````````````````
Python itself has a good support for methods accepting any
number of arguments. The same syntax works in libraries and, as
the examples below show, it can also be combined with other ways of
specifying arguments:

.. sourcecode:: python

  def any_arguments(*args):
      print "Got arguments:"
      for arg in args:
          print arg

  def one_required(required, *others):
      print "Required: %s\nOthers:" % required
      for arg in others:
          print arg

  def also_defaults(req, def1="default 1", def2="default 2", *rest):
      print req, def1, def2, rest

.. table:: Using keywords with a variable number of arguments
   :class: example

   ===========  ==============  =============  ============  ==============
    Test Case       Action         Argument      Argument       Argument 
   ===========  ==============  =============  ============  ==============
   Varargs      Any Arguments   \              \             \
   \            Any Arguments   argument       \             \
   \            Any Arguments   arg 1          arg 2         arg 2
   \            ...             arg 4          arg 5         \
   \            One Required    required arg   \             \
   \            One Required    required arg   another arg   yet another
   \            Also Defaults   required       \             \
   \            Also Defaults   required       these two     have defaults 
   \            Also Defaults   1              2             3
   \            ...             4              5             6
   ===========  ==============  =============  ============  ==============

Variable number of arguments with Java
``````````````````````````````````````
In Java, there is no syntax for a variable number of arguments, but Robot
Framework has its own support for them. If the last argument in a keyword
signature is an array, all leftover arguments are packed into
it. This also works, if the keyword is used with one argument less than
the actual number of arguments in the signature - in this case the
array at the end will be empty. 

This system has one limitation: it only works if the method has one
signature. Thus it is not possible to have a Java keyword that has
both the default values and a variable number of arguments. Of course,
having the required values with a variable number of arguments is
possible, as the examples below illustrate:

.. sourcecode:: java

  public void anyArguments(String[] args) {
      System.out.println("Got arguments:");
      for (int i; i < args.length; i++) {
          System.out.println(args[i]);
      }
  }

  public void oneRequired(String required, String[] others) {
      System.out.println("Required: " + required + "\nOthers:");
      for (int i; i < others.length; i++) {
          System.out.println(others[i]);
      }
  }

Argument types
''''''''''''''

Normally keyword arguments come to Robot Framework as strings. If
keywords require some other types, it is possible to either use
variables_ or convert strings to required types inside keywords. With
`Java keywords`__ base types are also coerced automatically.

__ `Argument types with Java`_

Argument types with Python
``````````````````````````
Because arguments in Python do not have any type information, there is
no possibility to automatically convert strings to other types when
using Python libraries. Calling a Python method implementing a keyword
with a correct number of arguments always succeeds, but the execution
fails later if the arguments are incompatible. Luckily with Python it
is simple to convert arguments to suitable types inside keywords:

.. sourcecode:: python

  def connect_to_host(address, port=25):
      port = int(port)
      # ...

Argument types with Java
````````````````````````
Arguments to Java methods have types, and starting from Robot
Framework 2.1 all the base types are handled automatically. This
means that arguments that are normal strings in the test data are
coerced to correct type at runtime. The types that can be coerced
are:

- integer types (:code:`byte`, :code:`short`, :code:`int`, :code:`long`)
- floating point types (:code:`float` and :code:`double`)
- the :code:`boolean` type
- object versions of the above types e.g. :code:`java.lang.Integer`

The coercion is done for arguments that have the same or compatible
type across all the signatures of the keyword method. In the following
example, the conversion can be done for keywords :code:`doubleArgument`
and :code:`compatibleTypes`, but not for :code:`conflictingTypes`.

.. sourcecode:: java
  
   public void doubleArgument(double arg) {}

   public void compatibleTypes(String arg1, Integer arg2) {}
   public void compatibleTypes(String arg2, Integer arg2, Boolean arg3) {}

   public void conflictingTypes(String arg1, int arg2) {}
   public void conflictingTypes(int arg1, String arg2) {}

The coercion works with the numeric types if the test data has a
string containing a number, and with the boolean type the data must
contain either string :code:`true` or :code:`false`. Coercion is only
done if the original value was a string from the test data, but it is
of course still possible to use variables containing correct types with
these keywords. With keywords having conflicting signatures using
variables is the only option.

.. table:: Using automatic type coercion
   :class: example

   ===========  =================  =============  ==========  =====================
    Test Case         Action          Argument     Argument        Argument 
   ===========  =================  =============  ==========  =====================
   Coercion     Double Argument    3.14
   \            Double Argument    2e16                       # scientific notation
   \            Compatible Types   Hello, world!  1234          
   \            Compatible Types   Hi again!      -10         true
   \
   No Coercion  Double Argument    ${3.14}                         
   \            Conflicting Types  1              ${2}        # must use variables
   \            Conflicting Types  ${1}           2              
   ===========  =================  =============  ==========  =====================


Communicating with Robot Framework
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After a method implementing a keyword is called, it can use any
mechanism to communicate with the system under test. It can then also
send messages to Robot Framework's log file, return information that
can be saved to variables and, most importantly, report if the
keyword passed or not. 

Reporting keyword status
''''''''''''''''''''''''

Reporting keyword status is done simply using exceptions. If an executed
method raises an exception, the keyword status is :msg:`FAIL`, and if it
returns normally, the status is :msg:`PASS`.

The error message shown in logs, reports and the console is created
from the exception type and its message. With generic exceptions (for
example, :code:`AssertionError`, :code:`Exception`, and
:code:`RuntimeError`), only the exception message is used, and with
others, the message is created in the format :msg:`ExceptionType:
Actual message`. In both cases, it is important for the users that the
exception message is as informative as possible.

If the error message is longer than 40 lines, it will be automatically
cut from the middle to prevent reports from getting too long and
difficult to read. The full error message is always shown in the log
message of the failed keyword.

The traceback of the exception is also logged using :msg:`DEBUG` `log level`_.
These messages are not visible in log files by default because they are very
rarely interesting for normal users. When developing libraries, it is often a
good idea to run tests using :cli:`--loglevel DEBUG`.

Stopping test execution
'''''''''''''''''''''''

Starting from Robot Framework 2.5 it is possible to fail a test case so that
`the whole test execution is stopped`__. This is done simply by having a special
:code:`ROBOT_EXIT_ON_FAILURE` attribute with :code:`True` value set on the 
exception raised from the keyword. This is illustrated in the examples below.

Python:

.. sourcecode:: python

    class MyFatalError(RuntimeError):
        ROBOT_EXIT_ON_FAILURE = True

Java:

.. sourcecode:: java

    public class MyFatalError extends RuntimeException {
        public static final boolean ROBOT_EXIT_ON_FAILURE = true;
    } 

__ `Exit on failure`_

Continuing test execution dispite of failure
''''''''''''''''''''''''''''''''''''''''''''

Starting from Robot Framework 2.5 it is possible to keep executing test
case even in case of a failure. This is done via keyword 
`Run Keyword And Continue On Failure` or by raising an exception with
a special :code:`ROBOT_CONTINUE_ON_FAILURE` attribute with :code:`True`
value set from the keyword. The latter is illustrated in the examples below.

Python:

.. sourcecode:: python

    class MyContinuableError(RuntimeError):
        ROBOT_CONTINUE_ON_FAILURE = True

Java:

.. sourcecode:: java

    public class MyContinuableError extends RuntimeException {
        public static final boolean ROBOT_CONTINUE_ON_FAILURE = true;
    }


Logging information
'''''''''''''''''''

Exception messages are not the only way to give information to the
users. In addition to that, methods can also send messages to `log
files`_ simply by writing to standard output (stdout) or standard
error (stderr), and they can even use different `log levels`_.

By default, everything written by a method into standard output is written
to the log file as a single entry with the log level
:msg:`INFO`. Messages written into standard error are handled similarly
otherwise, but they are echoed back to the original stderr after the
keyword execution has finished. It is thus possible to use stderr if you need
some messages to be visible on the console where tests are executed.

To use other log levels than :msg:`INFO`, or to create several
messages, specify the log level explicitly by embedding the level into
the message in the format :msg:`*LEVEL* Actual log message`, where
:msg:`*LEVEL*` must be in the beginning of a line and :msg:`LEVEL` is
one of the available logging levels :msg:`TRACE`, :msg:`DEBUG`,
:msg:`INFO`, :msg:`WARN` and :msg:`HTML`.

Warnings
````````
Starting from Robot Framework 2.1 messages with :msg:`WARN` level are
automatically written into `the console and into separate Test Execution
Errors section`__ in log files. This makes warnings more visible than
other messages and allows using them for reporting important but 
non-critical problems to users.

{'fraction_non_alphanumeric': 0.10616017148680465, 'fraction_numerical': 0.004111466423024212, 'mean_word_length': 3.4371248148436893, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2370368', 'n_tokens_mistral': 14521, 'n_tokens_neox': 13658, 'n_words': 7223}