class Roby::Test::TestCase

This is the base class for running tests which uses a Roby control loop (i.e. plan execution).

Because configuration and planning can be robot-specific, parts of the tests can also be splitted into generic parts and specific parts. The TestCase.robot statement allows to specify that a given test case is specific to a given robot, in which case it is ran only if the call to scripts/test specified a robot which matches (i.e. same name and type).

Finally, two other mode of operation control the way tests are ran

simulation

if the --sim flag is given to scripts/test, the tests are ran under simulation. Otherwise, they are run in live mode (see Roby::Application for a description of simulation and live modes). It is possible to constrain that a given test method is run only in simulation or live mode with the TestCase.sim and TestCase.nosim statements:

sim :sim_only
def test_sim_only
end

nosim :live_only
def test_live_only
end
interactive

Sometime, it is hard to actually assess the quality of processing results automatically. In these cases, it is possible to show the user the result of data processing, and then ask if the result is valid by using the user_validation method. Nonetheless, the tests can be ran in automatic mode, in which the assertions which require user validation are simply skipped. The --interactive or -i flags of scripts/test specify that user interaction is possible.

Attributes

app_setup[R]

Public Class Methods

apply_robot_setup() { || ... } click to toggle source

Loads the configuration as specified by TestCase.robot

# File lib/roby/test/testcase.rb, line 66
def self.apply_robot_setup
    app = Roby.app

    name, kind, block = app_setup
    # Ignore the test suites which use a different robot
    if name || kind && (app.robot_name && 
        (app.robot_name != name || app.robot_type != kind))
        Test.info "ignoring #{self} as it is for robot #{name} and we are running for #{app.robot_name}:#{app.robot_type}"
        return
    end
    if block
        block.call
    end

    yield if block_given?
end
nosim(*names) click to toggle source

Do not run test_name inside a simulation environment test_name is the name of the method without test_. For instance:

nosim :init
def test_init
end

See also TestCase.sim

# File lib/roby/test/testcase.rb, line 148
def self.nosim(*names)
    names.each do |test_name|
        config = (methods_config[test_name.to_s] ||= Hash.new)
        config[:mode] = :nosim
    end
end
robot(name, kind = name, &block) click to toggle source

Sets the robot configuration for this test case. If a block is given, it is called between the time the robot configuration is loaded and the time the test methods are started. It can therefore be used to change the robot configuration for the need of this particular test case

# File lib/roby/test/testcase.rb, line 61
def self.robot(name, kind = name, &block)
    @app_setup = [name, kind, block]
end
sim(*names) click to toggle source

Run test_name only inside a simulation environment test_name is the name of the method without test_. For instance:

sim :init
def test_init
end

See also TestCase.nosim

# File lib/roby/test/testcase.rb, line 163
def self.sim(*names)
    names.each do |test_name|
        config = (methods_config[test_name.to_s] ||= Hash.new)
        config[:mode] = :sim
    end
end

Public Instance Methods

automatic_testing?() click to toggle source

Returns true if user interaction is to be disabled during this test

# File lib/roby/test/testcase.rb, line 97
def automatic_testing?
    Roby.app.automatic_testing?
end
dataset_file_path(dataset_name, file) click to toggle source

Returns the full path of the file name into which the log file file should be saved to be referred to as the dataset_name dataset

# File lib/roby/test/testcase.rb, line 211
def dataset_file_path(dataset_name, file)
    path = File.join(datasets_dir, dataset_name, file)
    if !File.file?(path)
        raise "#{path} does not exist"
    end

    path
rescue
    flunk("dataset #{dataset_name} has not been generated: #{$!.message}")
end
dataset_prefix() click to toggle source

The directory into which the datasets generated by the current testcase are to be saved.

# File lib/roby/test/testcase.rb, line 206
def dataset_prefix
    "#{Roby.app.robot_name}-#{self.class.name.gsub('TC_', '').underscore}-#{@method_name.gsub(/(?:test|dataset)_/, '')}"
end
datasets_dir() click to toggle source

The directory in which datasets are to be saved

# File lib/roby/test/testcase.rb, line 201
def datasets_dir
    "#{Roby.app.app_dir}/test/datasets" 
end
planner() click to toggle source

Returns a fresh MainPlanner object for the current plan

# File lib/roby/test/testcase.rb, line 84
def planner
    MainPlanner.new(plan)
end
progress(value, max = nil) click to toggle source

Progress report for the curren test. If max is given, then value is assumed to be between 0 and max. Otherwise, value is a float value between 0 and 1 and is displayed as a percentage.

# File lib/roby/test/testcase.rb, line 104
def progress(value, max = nil)
    if max
        print "\rprogress: #{value}/#{max}"
    else
        print "\rprogress: #{"%.2f %%" % [value * 100]}"
    end
    STDOUT.flush
end
sampling(*args, &block) click to toggle source
# File lib/roby/test/testcase.rb, line 250
def sampling(*args, &block); Test.sampling(engine, *args, &block) end
save_dataset(files = nil, suffix = '') click to toggle source

Saves file, which is taken in the log directory, in the test/datasets directory. The data set is saved as 'robot-testname-testmethod-suffix'

# File lib/roby/test/testcase.rb, line 227
def save_dataset(files = nil, suffix = '')
    destname = dataset_prefix
    destname << "-#{suffix}" unless suffix.empty?

    dir = File.join(datasets_dir, destname)
    if File.exists?(dir)
        relative_dir = dir.gsub(/^#{Regexp.quote(Roby.app.app_dir)}/, '')
        unless STDIN.ask("\r#{relative_dir} already exists. Delete ? [N,y]", false)
            raise "user abort"
        end
        FileUtils.rm_rf dir
    end
    FileUtils.mkdir_p(dir)

    files ||= Dir.entries(Roby.app.log_dir).find_all do |path|
        File.file? File.join(Roby.app.log_dir, path)
    end

    [*files].each do |path|
        FileUtils.mv "#{Roby.app.log_dir}/#{path}", dir
    end
end
stats(*args, &block) click to toggle source
# File lib/roby/test/testcase.rb, line 251
def stats(*args, &block); Test.stats(*args, &block) end
user_interaction() { || ... } click to toggle source
# File lib/roby/test/testcase.rb, line 113
def user_interaction
    return unless automatic_testing?

    test_result = catch(:validation_result) do
        yield 
        return
    end
    if test_result
        flunk(*test_result)
    end
end
user_validation(msg) { || ... } click to toggle source

Ask for user validation. The method first yields, and then asks the user if the showed dataset is nominal. If the tests are ran in automated mode (automatic_testing? returns true), it does nothing.

# File lib/roby/test/testcase.rb, line 129
def user_validation(msg)
    return if automatic_testing?

    assert_block(msg) do
        STDOUT.puts "Now validating #{msg}"
        yield

        STDIN.ask("\rIs the result OK ? [N,y]", false)
    end
end