Qst Documentation

Qst is a firmware test automation suite for embedded devices. It uses the QML language to describe and implement test cases. QML is mainly a declarative programming language, but it can be enriched with Javascript.

Usage

This document explains most features of Qst and shows how to use them. It is a complete walk-through and will take about 15 minutes.

Qst makes use of the QML language, a declarative language mixed with Javascript. The language is very intuitive, but you might want to have a look at the QML language reference or keep it open in a separate browser tab.

We will use the terms item and component a lot. An item refers to a data type whereas component usually refers to a specific instance of an item.

Running a simple test case

Let us now get our hands dirty and have a look at a trivial test case. Every test case is defined by a Testcase component and is characterized by at least 2 things:

  • a name that serves as an identifier,
  • a run() function which implements sequential test steps.

The name must be unique across the whole project and must be a plain string. The run() function may have arbitrary execution length and contain blocking and non-blocking function calls. The Testcase component is put into a file of an arbitrary name and in its simplest form it would look as follows:

simple-passing-test.qml
import qst 1.0

Testcase {
    name: "simple-passing-test"

    function run() {
        /* ... */
    }
}

The above test case does not do anything useful. It specifies a name and contains an empty run() function. This is equal to a test case without any failure, so it will simply pass. We will now execute simple-passing-test.qml by typing the following command in a terminal:

$ qst run --file simple-passing-test.qml
PASS, simple-passing-test,,,

Qst prints a line of comma-separated values containing the test result and the name of the test case. We will discuss the remaining commas in a second.

Now let’s make the test case fail. For that purpose, Qst offers a couple of helper services of which Qst with its verification functions Qst::compare() and Qst::verify() is the most important one:

simple-failing-test.qml
1
2
3
4
5
6
7
8
9
import qst 1.0

Testcase {
    name: "simple-failing-test"

    function run() {
        Qst.verify(false)
    }
}

We execute the test, using a slightly shorter command line than above:

$ qst run -f simple-failing-test.qml
FAIL, simple-failing-test, simple-failing-test, simple-failing-test.qml:7, verify() failed

Qst outputs test results in a comma-separated line with the following elements:

  • result of the test case,
  • name of the test case,
  • name of the current active component (on fail only),
  • file location of the failure (on fail only),
  • error message (on fail only)

We know the result and the name already from the simple-passing-test.qml example. The other elements are only shown when a test case does not pass. In our very simple example, the test case is the only active component. More complex test cases might form a component tree structure, hence the 3rd column. The current location is the caller position of a verification function. The message in the last column comes from the failing verification function and is either set by hand or automatically created.

Now we know how to set up a test case and how to run it. Still, it doesn’t do anything useful. We need to connect it to the outside world and fill it with life.

Adding probe components

Probes connect Qst to the environment, for instance to the file system and other programs on the computer or even to external hardware. Probes are not a special language construct, but pure QML components with properties, methods, signals and slots.

A versatile probe item is the ProcessProbe. It can invoke programs on the local computer and monitor their execution. A very simple test case that runs GNU Make on a Makefile in the current folder would look like this:

makefile-test-simple.qml
import qst 1.0

Testcase {

    name: "makefile-test-simple"

    ProcessProbe {
        id: make
        program : "/usr/bin/make"
        workingDirectory: path
        arguments: [
            "-f", path + "/Makefile",
            "all"
        ]
    }

    function run() {
        make.start()
        make.waitForFinished(10)
        Qst.compare(make.exitCode, 0,
            "Build did not succeed: " + make.readAllStandardError())
    }
}

This example demonstrates the following new elements:

  • It instantiates a nested component of the type ProcessProbe and assigns custom values to its properties.
  • The nested process probe is assigned an id attribute so that it can be referenced.
  • The global path context property is used which always points the physical directory of the current file.

Various other probe items exist. For a complete list, have a look at the reference documentation.

Extending and re-using components

The above test case makefile-test-simple.qml is not re-usable in this form because all parameters are hard-coded. Consider a project with a bunch of makefiles. It would be cumbersome to re-write the whole test case for each makefile. Instead, we can turn the test case into a re-usable component by defining additional properties:

MakefileTestcase.qml
import qst 1.0

Testcase {

    property string makefile : path + "/Makefile"
    property string target: "all"
    property int timeout : 10

    ProcessProbe {
        id: make
        program : (Qst.hostOs === "windows") ? "gmake.exe" : "make"
        workingDirectory: path
        arguments: [
            "-f", makefile,
            target
        ]
    }

    function run() {
        make.start()
        make.waitForFinished(timeout)
        Qst.compare(make.exitCode, 0,
            "Build did not succeed: " + make.readAllStandardError())
    }
}

When saving it to a file MakefileTestcase.qml, it is automatically available as component type MakefileTestcase in other qml files located in the same directory. Based upon MakefileTestcase.qml, we can now create multiple test case files in the following form:

test-app-build.qml
import qst 1.0

MakefileTestcase {
    name: "test-app-build"
    makefile: path + "/app.mak"
}
test-lib-build.qml
import qst 1.0

MakefileTestcase {
    name: "test-lib-build"
    makefile: path + "/lib.mak"
}

Later we will learn a way to define multiple test case in one document.

Custom properties are also helpful in large test cases. Instead of hard-coding parameters everywhere in-line, it is better to to put them upfront to make the test case more readable. This applies to all components in general and is common practise in QML.

Attaching signal handlers

In many probes and test cases we might observe onXXX: {...} constructs, for instance:

Testcase {
    /* ... */
    onCreated: {
        // prepare external resources
    }
}

Signal handlers are always written in the form on<CapitalizedSignal>. Signals and signal handlers are a core concept of the QML language and fall in 1 of 3 categories:

  1. explicitly defined signals, like ProcessProbe::finished(),
  2. implicitly defined property change signals,
  3. attached signals added by other components.

Signal handlers may contain arbitrary JavaScript code, but they have run-to- completion semantics and must never do blocking calls. You may follow above links to read more about this topic. Let us now have a look, how we can utilize signal handlers in a Qst project.

Our MakefileTestcase.qml file from above can only do one thing: invoke GNU make. But what if a test case is more complex and needs to invoke additional programs? In this case, it would be more benefitial to extend ProcessProbe instead of Testcase:

MakeProbe.qml
import qst 1.0

ProcessProbe {
    property string makefile : path + "/Makefile"
    property string target: "all"
    property int jobs: 1

    program : (Qst.hostOs === "windows") ? "gmake.exe" : "make"
    arguments: [
        "-f", makefile,
        "-j", jobs,
        target
    ]
    workingDirectory: path

    // Explicitly defined by ProcessProbe
    onFinished: {
        Qst.compare(exitCode, 0, readAllStandardError())
    }

    // Implicitly defined property change signal
    onJobsChanged: {
        Qst.verify(jobs <= 4, "The maximum number of jobs is 4.")
    }

    // Attached by Testcase
    Testcase.onFinished: {
        if (state === ProcessProbe.Running) {
            terminate()
            Qst.verify(false, "Make was still running.")
        }
    }

}

The MakeProbe.qml component can now be included even multiple times like this:

test-multi-build.qml
import qst 1.0

Testcase {
    name: "test-multi-build"

    MakeProbe {
        id: app
        name: "make-app"
        makefile: path + "/app.mak"
        jobs: 5
    }

    MakeProbe {
        id: lib
        name: "make-lib"
        makefile: path + "/lib.mak"
        jobs: 5
    }

    function run() {
        app.start()
        app.waitForFinished(20)
        lib.start()
        lib.waitForFinished(20)
    }

}

As we can see in MakeProbe.qml, implicit and explicit signal handlers must be defined in the scope of the signal’s owner component. For instance, onJobsChanged would not work outside MakeProbe. In cases where we need to handle a signal of a component that is not defined in the current component, we can use SignalProbe as shown in the ExtendedTestcase.qml example. It is also possible to use the Connections item from the QtQml package.

Using constraints for continuous evaluation

In the MakeProbe.qml example we have learned how signal handlers can be used for on-going verification. We do not have to think about them in the run() function, they work silently in the background.

Constraints follow the same principle, but are a bit more formalized and declarative. They make the test case fail immediately when they are violated. Constraints are usually connected to signals like the DurationConstraint or bound to properties like the ValueRangeConstraint.

Take the following test case as an example:

import qst 1.0

Testcase {
    property int responseTime: 0

    onResponseTimeChanged: {
        Qst.verify((responseTime >= 4) && (responseTime =< 8),
            "responseTime (" + responseTime
            + ") is not in the expected range.")
    }

    function run() {
        // ...
    }
}

The property responseTime could be validated by the help of an implicit property changed signal handler and Qst verification functions. But we could also use a constraint and improve the readability of the test case:

import qst 1.0

Testcase {
    property int responseTime: 0

    ValueRangeConstraint {
        value: responseTime
        minValue: 4
        maxValue: 8
    }

    function run() {
        // ...
    }
}

Structuring projects

Until now we have only discussed single test cases whereas a real project would contain many of them. Qst provides the Project item for this purpose. A Project component can reference all test cases and serves as the main file of the project:

Project {
    name: "referencing-project"
    references: [
        "testcase-file-1.qml",
        "testcase-file-2.qml",
        /* ... */
    ]
}

It is also possible to put multiple Testcase components into a the same file by enclosing them in a Project component. This is especially useful when parametrizing and instantiating a generic test case multiple times:

SpecialTestcase.qml
Testcase {
    property int speed

    function run() {
        Qst.info("Speed is set to " + speed)
    }
}
project.qml
Project {
    name: "inline-project"
    SpecialTestcase { name: "tc-1"; speed: 10 }
    SpecialTestcase { name: "tc-2"; speed: 42000 }
    /* ... */
}

The Project component is automatically attached to any referenced file and can be accessed as project context property:

project.qml
Project {
    property string host: "http://secr.et"

    references: [
        "test-case-1.qml",
        /* ... */
    ]
}
test-case-1.qml
Testcase {
    name: "test-case-1"

    function run() {
        Qst.info(name + " is using " + project.host)
    }
}

Although the project property is shared across the whole project, test cases are not supposed to write to the project’s properties.

Working with profiles

Qst projects may be developed and executed by multiple developers on different computers. One usual problem in such setups are differing installation paths, serial numbers, ports, etc. . Putting machine-dependent values into project files would only complicate version control and collaboration:

Testcase {
    property string port: "COM77"   // ttyUSB3 on another computer

    /* ... */
}

Profiles solve that problem by collecting machine-dependent properties in a JSON file that remains on the developer’s computer:

uart-testing.json on computer 1
{
    "port": "COM77",
}
uart-testing.json on computer 2
{
    "port": "ttyUSB3",
}

The profile name is determined by the file name and selected as command line option when executing a test project:

$ qst run --file mytest.qml --profile uart-testing

Profile values can be accessed from anywhere in the project as profile:

Testcase {
    property string port: profile.port
}

Qst tries to load the he selected profile first from the project directory and if it could not be found, it searches in the »profiles« folder inside the Qst configuration directory. Additional profile search paths can be specified with --profile-directory or -P respectively:

$ qst run --f mytest.qml -p uart-testing -P /path/to/profiles

The latter option might be given multiple times.

Storing temporary files

Qst uses a working directory to store intermediate files during test execution. The directory is automatically created in the current folder and by default it has the format .<project-name>-<profile-name>-<hash>. Each test case will have a sub-folder with its name in the project working directory.

Let us assume a test project that:

  1. builds a firmware image,
  2. downloads it to the hardware,
  3. executes various tests on the hardware.

The directory layout of this imagined example project would look like:

.myproject-myprofile-e413c0f7
├── testcase-build
│   ├── object-1.o
│   ├── object-2.o
│   └── firmware.hex
├── testcase-flash
├── testcase-some-feature
└── testcase-other-feature
    └── log.txt

For the run command, the working directory can be overridden by the --working-directory command-line option. When run is executed multiple times and the working directory already exists, each test case sub-folder is wiped out before the Testcase::created() signal is emitted.

Tagging test cases for data-driven tests

In MakefileTestcase.qml and SpecialTestcase.qml we have already seen two ways to re-use and parameterize Testcase components. This can be cumbersome for larger amount of data. It might also be annoying to give each test case a different name while only some input parameters change, but not the test case itself.

Especially for data-driven testing, Qst provides the Matrix item. A matrix spans a n-dimensional parameter space that is then applied to a one or more test cases. Each data sample is called a tag and the combination of a tag and a Testcase is called a job.

The following example project defines a matrix with two dimensions, each containing a parameter array of length 2:

matrix-project.qml
import qst 1.0

Project {
    Matrix {
        Dimension {
            animal: [
                "cat",
                "dog"
            ]
        }

        Dimension {
            does: [
                "moans",
                "bites"
            ]
        }

        testcases: [ "tagged-test" ]
    }

    Testcase {
        name: "tagged-test"
        property string animal
        property string does

        function run() {
            Qst.info("The " + animal + " " + does + ".")
        }
    }

    Testcase {
        name: "normal-test"

        function run() {}
    }
}

Thus, the matrix expands to 4 different tag combinations:

dog bites dog moans
cat bites cat moans

When executing above project, the command line output looks as follows:

$ qst run -f matrix-project.qml
PASS, normal-test,,,
INFO, tagged-test 1ms2r6i [ cat moans ], , /matrix-project.qml:27, The cat moans.
PASS, tagged-test 1ms2r6i [ cat moans ],,,
INFO, tagged-test 17tca19 [ dog bites ], , /matrix-project.qml:27, The dog bites.
PASS, tagged-test 17tca19 [ dog bites ],,,
INFO, tagged-test 0ni1i5d [ cat bites ], , /matrix-project.qml:27, The cat bites.
PASS, tagged-test 0ni1i5d [ cat bites ],,,
INFO, tagged-test 07cs7hy [ dog moans ], , /matrix-project.qml:27, The dog moans.
PASS, tagged-test 07cs7hy [ dog moans ],,,

Specifying dependencies between test cases

The default execution order of test cases is undefined in Qst. But in practise, a test case B might require the completion of another test case A. Such dependencies can be expressed with the Depends item as shown in the following code snippet:

simple-depends-depends.qml
import qst 1.0

Project {

    Testcase {
        name: "A"

        function run() {}
    }

    // Has to wait until A completes.
    Testcase {
        name: "B"

        Depends { name: "A" }

        function run() {}
    }
}

Of course the test cases A and B can be defined in different files and each test case can have multiple dependencies.

Sometimes it might also be desired to access data from a preceding test. By the help of the Exports item, a test case can specify which data is to be forward to dependent test cases. This is not possible otherwise because test cases are isolated from each other do not share any memory.

Hardware probes

Qst can be connected to hardware in order to perform measurements or to control the device under test.

Texas Instruments Launchpad

The launchpad probe firmware converts a launchpad into a cheap real-time IO interface. Available are all pins on the board except the LEDs at DIO6 and DIO7 which are occupied by the probe firmware.

The probe firmware binaries are located in <QST_INSTALL_DIR>/share/qst/firmware and may be written to the hardware using Uniflash.

Supported launchpads:

Related probe items:

Related service items:

Reference

General

Command-line interface

Qst provides multiple command-line commands. They can be invoked as qst <command name>. The following commands are available:

run

Executes a test case or a test project and outputs the results.

Synopsis
qst run [options]
Description

The run command executes a Qst .qml file containing a Testcase or a Project component. The file is specified by the -f option.

Options
-d, --working-directory <path>

Use <path> as working directory during test case execution. If the directory does not exist, it is being created. By default, a directory with the name .<project-name>-<profile-name>-<hash> is created in the current path.

-f, --file <file>

Use <file> as project file. If <file> is a directory and contains a single file ending in .qml, that file will be used. If this option is not given at all, the behavior is the same as for --file ./.

-h, --help

Displays this help.

-I, --import <path>

Add <path> as a directory where the engine searches for installed modules in a URL-based directory structure.

The path may be a local file system directory, a Qt Resource path (:/imports), a Qt Resource url (qrc:/imports) or a URL.

-p, --profile <name>

Load a profile from <name>.json and attach it to the QML root context. Matching profiles are searched in the directories specified by -P or in the project directory or in the config directory’s profile sub-directory (in this order).

-P, --profile-directory <path>

When looking for profiles, search first in <path>. This option might be given multiple times.

version

Prints the version of Qst to stdout.

Synopsis
qst version
Description

Prints the version of Qst to stdout.

Options

This command takes no options.

Language reference

Qst makes use of the QML language, a declarative language mixed with Javascript. The official QML language reference eplains all core concepts in detail. In difference to a regular QML interpreter, Qst analyses the the documents before it executes them and makes additions to the QML runtime environment. It expects a certain structure and enforces some rules. The purpose of this document is, to eplain all differences.

Context properties

The following properties are automatically attached by the Qst QML engine to every loaded documented unless unless otherwise stated.

string path

Absolute path of the directory where the current file is located.

var profile

Reference to the global profile object if a profile is set from command line.

Project project

Reference to the global project object. When running a document with a Testcase component, an empty project item is created.

Testcase test

Reference to the owner test case. This property is available in Testcase components and in other stand-alone component definitions such as shown in the MakeProbe.qml example. It is not available in documents containing a Project component.

QML data types

QML types for properties used in this reference documentation. Basic QML types are also explained in the QML language reference.

bool

Boolean value. Can be either true or false.

double

64 bit (double precision) floating point number.

int

32 bit signed whole number.

type list

List of QML objects. See also http://doc.qt.io/qt-5/qml-list.html

type signal

A reference to a signal attribute of a component. It is not a dedicated data type, but rather stored as var. signal objects provide a connect() and disconnect() method to connect to a destination function. They are also functors and can be called like a function in order to invoke connected signal handlers.

type string

Free form text string. See also http://doc.qt.io/qt-5/qml-string.html

type stringlist

An array of strings. See also http://doc.qt.io/qt-5/qml-var.html

type var

Generic property type. Can hold any data type, but usually used for objects and arrays. See also http://doc.qt.io/qt-5/qml-var.html

Component Item

class Component

Base type for various dynamic items such as probes.

Locations:Component, Testcase
Nested items:Component, QtObject
Inherited by:ProcessProbe, PinProbe, SignalProbe, UniflashProbe
Properties:name

Detailed Description

Component is used as a base type for all kinds of dynamic items in test cases such as probes and other helpers. Component items may define their own properties, methods, signals and signal handlers. All probe items are based upon Component.

Use this item whenever you want to implement re-usable components for the use in Testcase items.

Properties

string name
Default:typename-number

Name of the component. When not set, Qst will deduce the final typename and add a counter so that the component is assigned a unique name. For instance, when implementing MyProbe.qml based on Component, the default name for probe items will be myprobe-x where x is a counter value.

This value does currently only have an effect in error messages.

Depends Item

class Depends

Describes dependencies between Testcase items.

Locations:Testcase
Properties:alias, name

Detailed Description

The Depends defines a dependency on another test case specified by name. In its simplest form, it specifies only a precedence relation as for instance in the following example:

simple-depends-depends.qml
import qst 1.0

Project {

    Testcase {
        name: "A"

        function run() {}
    }

    // Has to wait until A completes.
    Testcase {
        name: "B"

        Depends { name: "A" }

        function run() {}
    }
}
Accessing properties of dependencies

In the above example, test case B may want to access results and properties of A. The Depends item attaches a reference of selected properties from A to B. These properties are available in B through the Testcase::dependencies property as shown in the following example:

simple-exports.qml
import qst 1.0

Project {

    Testcase {
        name: "A"

        Exports {
            id: exports
            property string result
        }

        function run() {
            exports.result = "excellent"
        }
    }

    Testcase {
        name: "B"

        Depends {
            name: "A"
        }

        function run() {
            Qst.info("A was " + dependencies.A[0].result)
        }
    }
}

After completion of A, Qst copies the properties of the Exports item over to B. Test case B can access them through the dependencies property. Only basic QML types are considered for exporting which avoids side effects.

Dependencies and tags

When being assigned to a Matrix item, a testcase may be expanded to multiple jobs. The Depends item allows to control which job instances of one test case A match which job instances of a test case B. It comes in two matching flavours. Consider the following Matrix project:

depends-project-with-matrix.qml
import qst 1.0

Project {

    Matrix {
        Dimension {
            board: [ "board-1", "board-2" ]
        }
        Dimension {
            config: [ "debug", "release" ]
        }
        testcases: [
            "A",
            "implicit"
        ]
    }

    references: [
        "explicit.qml",
        "implicit.qml"
    ]

    Testcase {
        name: "A"
        id: a
        property string board
        property string config

        Exports {
            id: exports
            property string firmwarePath
        }

        function run() {
            exports.firmwarePath = board + "-" + config + ".elf"
        }
    }
}

The project in depends-project-with-matrix.qml consists of 3 test cases, 2 of which depend on a test case A. The referenced test cases will be explained in the following sub-sections.

Explicit matching

The Depends item specifies all tag keys of the depending test case. This matching type is always unambiguous and is especially useful when a non-tagged test case depends only on certain jobs of a tagged one. Example:

explicit.qml (not tagged) depends only on some instances of A
import qst 1.0

Testcase {
    name: "explicit"
    id: b

    Depends {
        name: "A"
        board: [
            "board-1",
            "board-2"
        ]
        config: "debug"
    }

    function run() {
        var paths = dependencies.A.reduce(function(acc, value) {
            acc += value.firmwarePath + " "
            return acc
        }, "")
        Qst.info("depends on " + paths)
    }
}
$ qst run -f depends-project-with-matrix.qml | grep -e explicit -e " A "
PASS, A 0000000 [ board-1 debug ],,,
PASS, A 0000001 [ board-2 debug ],,,
PASS, A 0000002 [ board-1 release ],,,
PASS, A 0000003 [ board-2 release ],,,
INFO, explicit, , explicit.qml:21, depends on board-1-debug.elf board-2-debug.elf
PASS, explicit,,,
Implicit matching

The Depends item specifies none of the tags of a depending test case. In this case, the matching behavior depends on whether the test case and the dependency are tagged or not. Non-tagged example:

implicit.qml The test case implicit (not tagged) depends on all instances of A (tagged).
import qst 1.0

Testcase {
    name: "implicit"
    id: b

    property string board
    property string config

    Depends {
        name: "A"
    }

    function run() {
        var paths = dependencies.A.reduce(function(acc, value) {
            acc += value.firmwarePath + " "
            return acc
        }, "")
        Qst.info("depends on " + paths)
    }
}
$ qst run -f depends-project-with-matrix.qml | grep -e implicit -e " A "
PASS, A 0000000 [ board-1 debug ],,,
PASS, A 0000001 [ board-2 debug ],,,
PASS, A 0000002 [ board-1 release ],,,
PASS, A 0000003 [ board-2 release ],,,
INFO, implicit 0000004 [ board-1 debug ],, implicit.qml:19, depends on board-1-debug.elf
PASS, implicit 0000004 [ board-1 debug ],,,
INFO, implicit 0000005 [ board-2 debug ],, implicit.qml:19, depends on board-2-debug.elf
PASS, implicit 0000005 [ board-2 debug ],,,
INFO, implicit 0000006 [ board-1 release ],, implicit.qml:19, depends on board-1-release.elf
PASS, implicit 0000006 [ board-1 release ],,,
INFO, implicit 0000007 [ board-2 release ],, implicit.qml:19, depends on board-2-release.elf
PASS, implicit 0000007 [ board-2 release ],,,
B (not tagged) depends on A (not tagged):
 There is only a single instance of A and B.
B (not tagged) depends on A (tagged):
 There is only a single instance of B and it matches all instances of A.
B (tagged) depends on A (not tagged):
 Every job instance of B matches the same single instance of A.
B (tagged) depends on A (tagged):
 Every job instance of B matches all jobs of A that have at least the same tags as B. If A and B are in the same matrix, then the resulting relationship is usually 1:1.

Properties

string alias

The name may not be valid JavaScript identifier or multiple Depends items may reference the same Testcase::name. In this case, alias specifies the identifier under which exported values can be accessed through the Testcase::dependencies property.

This property must be a plain string and a valid JavaScipt identifer.

string name

The name of the depending test case. It must match with an existing Testcase::name.

This property must be a plain string and cannot be empty.

Dimension Item

class Dimension

Defines a value span within a Matrix.

Locations:Matrix

Detailed Description

The Dimension item defines a span of one or more property values. It can only exist in a Matrix context. The size of a Dimension is determined by its values. The item does not have any predefined properties and it is not intended to declare new properties using the property keyword. Instead, it is enough to write a property name and assign values to it.

The property name must be present in all test cases that the Matrix is applied to. If the test case does not have a property with that name, an error is thrown.

The values must be supplied either in an array with a defined length or as a trivial type.

Single array

A typical Dimension component defines a single property in array format:

Matrix {
    testcases: "*"

    Dimension {
        mcu: [
            "cc1312R1",
            "cc1352R1",
            "cc1352P1",
        ]
    }
}
Multiple arrays

It is also possible to define multiple arrays in one dimension as long as they have equal length. The values are read as tuples, for instance:

Dimension {
    mcu: [
        "cc1312R1",
        "cc1352R1",
        "cc1352P1",
    ]
    board: [
        "CC1312R1_LAUNCHXL",
        "CC1352R1_LAUNCHXL",
        "CC1352P1_LAUNCHXL"
    ]
}

results in the tag pairs:

  • Testcase { mcu: "cc1312R1"; board: "CC1312R1_LAUNCHXL"
  • Testcase { mcu: "cc1352R1"; board: "CC1352R1_LAUNCHXL"
  • Testcase { mcu: "cc1352P1"; board: "CC1352P1_LAUNCHXL"
Arrays and trivial values

For convenience it is possible to shrink arrays with identical values as long as the Dimension contains an array that determines its length:

Dimension {
    mcu: [
        "cc1312R1",
        "cc1352R1",
        "cc1352P1",
    ]
    family: "cc13x2" // cloned 3 times
}

The above Dimension results in:

  • Testcase { mcu: "cc1312R1"; family: "cc13x2" }
  • Testcase { mcu: "cc1352R1"; family: "cc13x2" }
  • Testcase { mcu: "cc1352P1"; family: "cc13x2" }
References and complex expressions

References to other properties are allowed as well as referencing the whole array:

Matrix {
    id: matrix

    testcases: "*"

    property var animals: {
        var values = []
        values.push("cat")
        values.push("dog")
        return values
    }

    property string color: "white"

    Dimension {
        animal: matrix.animals
    }

    Dimension {
        attribute: [
            "brown",
            matrix.color
        ]
    }
}

It is currently only possible to evaluate JavaScript expressions by referencing other properties. The following example does not work:

// Not supported
Dimension {
    animals: {
        var values = []
        values.push("cat")
        values.push("dog")
        return values
    }
}

DurationConstraint Item

class DurationConstraint

Checks the time between two signal occurrences.

Inherits:Component
Properties:beginOn, duration, enabled endOn, evaluateOnFinished, evaluateOnValidation, maxDuration, minDuration. timedOut, valid
Methods:begin(), end()

Detailed Description

DurationConstraint measures the time between two signals beginOn and endOn. The methods begin() or end() may be used as an alternative if no signals are available. The expected duration is configured with minDuration and maxDuration.

The constraint has two stages: validation and evaluation. Validation happens immediately after the endOn signal has fired. In the same moment, the duration property is updated and shows the measured duration. Whether the duration is within the expected range, can be seen at the property valid.

During the evaluation stage, it is decided whether the test case is aborted. Evaluation can either happen immediately after validation (evaluateOnValidation is true) or just before the Testcase::finished() event (evaluateOnFinished is true). The enabled property switches measurement completely on and off.

Example for measuring the duration between two signals:

import qst 1.0

Testcase {

    ProcessProbe {
        id: process
        command: "sleep"
        arguments: [ 3 ]
    }

    DurationConstraint {
        id: constraint
        minDuration: 2.9
        maxDuration: 3.1

        beginOn: process.started
        endOn: process.finished
    }

    function run() {
        process.start()
        Qst.wait(4000)
    }

Example for monitoring a sequence of actions:

import qst 1.0

Testcase {

    DurationConstraint {
        id: constraint
        minDuration: 5
        maxDuration: 10
    }

    function run() {
        constraint.begin()

        // Now do something very time consuming...
        Qst.wait(20); // will be aborted because constraint
                      // is violated after 10 ms.
    }

Properties

signal beginOn
Default:undefined

Starts a measurement action. This property must either be QML signal or an object that defines a connect() method with a signal handler as parameter. When updating this property, the old signal will be disconnected.

See also: endOn, begin(), end()

double duration
Default:0.0

The measured timed between beginOn and endOn.

bool enabled
Default:true

When false, the signals beginOn and endOn do not have any effect and the constraint is neither validated nor evaluated.

signal endOn
Default:undefined

Ends a measurement cycle and triggers validation. This property must either be QML signal or an object that defines a connect() method with a signal handler as parameter. When updating this property, the old signal will be disconnected.

See also: beginOn, begin(), end()

bool evaluateOnFinished
Default:false

If true, the constraint will be evaluated by Qst just before Testcase::finished().

See also evaluateOnValidation

bool evaluateOnValidation
Default:true

If true, the test case will fail immediately when validation fails. If false, then the constraint will not be evaluated immediately. Instead, it will be evaluated on Testcase::finished().

See also evaluateOnFinished

double maxDuration
Default:0.0

Specifies the maximum allowed time between beginOn and endOn. The value must be greater or equal minDuration.

See also minDuration

double minDuration
Default:0.0

Specifies the minimum allowed time between beginOn and endOn. The value must be less or equal maxDuration.

See also maxDuration

bool timedOut
Default:false

Becomes true when the time between beginOn and endOn exceeds the specified duration range. This property is set back to false on each measurement interval.

bool valid
Default:false

Reflects whether duration is within the specified range.

Methods

void begin()

Equivalent to beginOn. Can be used to start a measurement manually or when no signal is available to attach to.

See also: end(), beginOn, endOn

void end()

Equivalent to beginOn. Can be used to start a measurement manually or when no signal is available to attach to.

See also: begin(), beginOn, endOn

Exports Item

class Exports

Forwards data to dependent Testcase items.

Locations:Testcase

Detailed Description

The Exports item helps the surrounding test case to forward results and additional data to dependent test cases. It requires a Depends item on the other side to access the forwarded results. Together, the Exports and the Depends item form a dataflow graph. The Exports item does not have any built-in properties. Here is an example:

simple-exports.qml
import qst 1.0

Project {

    Testcase {
        name: "A"

        Exports {
            id: exports
            property string result
        }

        function run() {
            exports.result = "excellent"
        }
    }

    Testcase {
        name: "B"

        Depends {
            name: "A"
        }

        function run() {
            Qst.info("A was " + dependencies.A[0].result)
        }
    }
}

After completion of A, Qst copies the properties of the Exports item over to B. Test case B can access them through the dependencies property. Only basic QML types are considered for exporting which avoids side effects.

Matrix Item

class Matrix

Replicates Testcase components with different property values.

Locations:Project, Testcase, document root
Nested items:Dimension
Properties:testcases

Detailed Description

The Matrix item allows to implement data-driven tests and to separate implementation from input data. It spans a space of values based on one or more Dimension items. The resulting value combinations are called tags. Each tag may be applied to one or more test cases depending on the testcases property.

matrix-project.qml
import qst 1.0

Project {
    Matrix {
        Dimension {
            animal: [
                "cat",
                "dog"
            ]
        }

        Dimension {
            does: [
                "moans",
                "bites"
            ]
        }

        testcases: [ "tagged-test" ]
    }

    Testcase {
        name: "tagged-test"
        property string animal
        property string does

        function run() {
            Qst.info("The " + animal + " " + does + ".")
        }
    }

    Testcase {
        name: "normal-test"

        function run() {}
    }
}

The Matrix component in matrix-project.qml has two dimensions, each containing an array of length 2. Thus, the matrix expands to 4 different tag combinations:

dog bites dog moans
cat bites cat moans
Matrix execution

A tagged test case is re-executed for each tag and every execution entity is called a job. The job order is generally undefined. Tagging has consequences on the test case’s execution:

  1. The test case name in the command line output is followed by the tag data and a hash of the tag data.
  2. The test case’s working directory name is expanded with the hash.

Above matrix-project.qml example results in the following output on command line:

$ qst run -f matrix-project.qml
PASS, normal-test,,,
INFO, tagged-test 1ms2r6i [ cat moans ], , /matrix-project.qml:27, The cat moans.
PASS, tagged-test 1ms2r6i [ cat moans ],,,
INFO, tagged-test 17tca19 [ dog bites ], , /matrix-project.qml:27, The dog bites.
PASS, tagged-test 17tca19 [ dog bites ],,,
INFO, tagged-test 0ni1i5d [ cat bites ], , /matrix-project.qml:27, The cat bites.
PASS, tagged-test 0ni1i5d [ cat bites ],,,
INFO, tagged-test 07cs7hy [ dog moans ], , /matrix-project.qml:27, The dog moans.
PASS, tagged-test 07cs7hy [ dog moans ],,,
Matrix in Project and in Testcase

A Matrix can be defined on two levels: on project level and on test case level. When defined in project scope, the testcases property specifies, to which test cases the Matrix applies. When defined inside a Testcase item, the Matrix implicitly applies to the surrounding test case only.

Matrix applies to multiple test cases.
import qst 1.0

Project {
    Matrix { ... }
    Testcase { ... }
    Testcase { ... }
    Testcase { ... }
    Testcase { ... }
}
Matrix applies to single test case.
import qst 1.0

Testcase {
    Matrix { ... }
}
Multiple matrices and overlap

It is possible to define multiple Matrix components both on Project and Testcase level and it is even allowed for different matrices to attach their tags to the same test cases. However, the resulting tag combinations must be distinct and must not shadow each other so that every job can be clearly identified by the combination of test case name and tags.

ambiguously-overlapping-matrices.qml: Testcase { color: "red" } would map to 3 different jobs.
// Matrices shadow each other.
Matrix {
    testcases: "*"
    Dimension {
        color: [ "red", "blue" ]
    }
}

Matrix {
    testcases: "*"
    Dimension {
        color: [ "red", "blue" ]
    }
    Dimension {
        speed: [ "fast", "slow" ]
    }
}
unambiguously-overlapping-matrices.qml:
// Matrices are compatible.
Matrix {
    testcases: "*"
    Dimension {
        color: [ "orange", "green" ]
    }
}

Matrix {
    testcases: "*"
    Dimension {
        color: [ "red", "blue" ]
    }
    Dimension {
        speed: [ "fast", "slow" ]
    }
}

Properties

stringlist testcases
Default:empty list

A list of test case names that the matrix is applied to. Entries may contain exact names as well as the wildcard characters * (match any string) and ? (match any character). Duplicate entries are ignored.

Example:

testcases : [
    "sometest", // Matches only "sometest"
    "test-*",   // Matches any testcase starting with "test-"
    "tc-??",    // Matches any testcase starting with "tc-" followed
                // by 2 letters.
]

This property is not writable when Matrix is defined inside a Testcase component as the matrix then implicitly applies to the surrounding test case only.

PinProbe Item

class PinProbe

Represents a digital IO pin on the launchpad probe board.

Inherits:Component
Enumerations:PullMode, Type, Value
Properties:ioid, port, pullMode, type, value

Detailed Description

A PinProbe component represents an IO pin on the launchpad probe board. It can be used to physically interface Qst to a Device Under Test (DUT) and stimulate/analyse digital hardware signals.

Each PinProbe item can be configured either as input or output. Additional pull-up or pull-down resistors may be activated for inputs. The output state is set by writing to the output property and events on the probe wire can be observed by attaching a signal handler to the valueChanged() signal.

Example:

import qst 1.0

// Assuming a DUT with an LED and a button and two wires of a
// launchpad probe board attached.
// On a falling edge of the button IO, the LED shall be turned on.
Testcase {
    name: "test-app"

    property string port: "ttyACM3"

    PinProbe {
        id: button
        port: test.port
        type: PinProbe.Write
        value: PinProbe.High
    }

    PinProbe {
        id: led
        port: test.port
        type: PinProbe.Read

        onValueChanged: {
            Qst.info("The LED value is now " + led.value);
        }
    }

    function run() {
        Qst.wait(50);
        Qst.compare(led.value, PinProbe.Low, "LED should be off but is on");
        // Stimulate button press
        button.value = PinProbe.Low;
        Qst.wait(5);
        Qst.compare(led.value, PinProbe.High, "LED should be on but is off");
    }
}

PinProbe currently only emits the valueChanged() signal. All other properties are assumed to be constant during application life time.

Enumerations

enum Type

Configures the pin direction.

enumerator Read

Configures the pin as input.

enumerator Write

Configures the pin as output.

enum PullMode

Whether internal pull resistors should be enabled or not.

enumerator PullDisabled

Pull resistors are disabled.

enumerator PullDown

Enables a pull-down resistor on the pin.

enumerator PullUp

Enables a pull-up resistor on the pin.

enum Value

The logic level on the hardware pin.

enumerator Low

Equals to 0 and false.

enumerator High

Equals to 1 and true.

enumerator Undefined

No value has been assigned to this pin yet.

Properties

int ioid
Default:0

Specifies the IO identifier on the probe board. The range is usually 0..31, but not all IOs might be available.

string port
Default:empty

The serial port identifier of the probe board. On Windows, this is usually COMx while on Linux systems ttyACMx or ttyUSBx is commonly used.

See also Xds::portFromSerial()

PullMode pullMode
Default:PullMode::PullDisabled

Configures the pin access direction. When configured to Type::Read, the pin probe will detect negative and positive edges on the pin.

Type type
Default:Type::Read

Configures the pin access direction. When configured to Type::Read, the pin probe will detect negative and positive edges on the pin.

Value value
Default:Value::Undefined

The current state of the pin. The property can be read from and written to. A write has no effect when the pin is configured as Type::Read. Although defined as an enumerator, values are implicitly converted to integers and booleans.

ProcessProbe Item

class ProcessProbe

Starts and watches processes.

Inherits:Component
Enumerations:ProcessError. State
Properties:arguments, exitCode, program state, workingDirectory
Methods:readAllStandardError(), readAllStandardOutput() start(), terminate(), waitForFinished() waitForStarted()
Signals:errorOccurred(), started(), finished()

Detailed Description

ProcessProbe can invoke external applications and communicate with them. It mirrors the API of QProcess.

The process to run is defined by the program property. Arguments are provided as a string list in the arguments property.

Example:

import qst 1.0

Testcase {

    ProcessProbe {
        id: make
        program : (Qst.hostOs === "windows") ? "gmake.exe" : "make"
        arguments: [
            "-j",
            "8"
        ]
    }

    function run() {
        make.start();
        make.waitForFinished(1701);
        Qst.compare(make.exitCode, 0, "Make did not succeed");
    }
}

Enumerations

enum ProcessError

Error events during process execution. Further information may be obtained with errorString().

enumerator Crashed

The process crashed some time after starting successfully.

enumerator FailedToStart

The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.

enumerator ReadError

An error occurred when attempting to read from the process. For example, the process may not be running.

enumerator Timedout

The last waitFor…() function timed out. The state of ProcessProbe is unchanged, and you can try calling waitFor…() again.

enumerator WriteError

An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.

enumerator UnknownError

An unknown error occurred.

enum State

Execution state of the process.

enumerator NotRunning

The process has not been started or it has already finished.

enumerator Starting

The process is starting, but it is not running yet.

enumerator Running

The process is running.

Properties

stringlist arguments

Process arguments in list format. Unlike on a shell, spaces do not separate arguments and thus, each argument must be a separate list entry. Escaping is required for arguments containing spaces.:

// Wrong
arguments: [ "--file My\ File.txt " ]

// Correct
arguments: [
    "--file",
    "My File.txt"
]
integer exitCode

The exit code of the last process that finished. This property is read-only.

string program

Path to an executable to run.

State state

The current execution state of the process.

string workingDirectory

Methods

string errorString()

Returns a human-readable description of the last error that occurred.

string readAllStandardError()

This function returns all data available from the standard error of the process.

string readAllStandardOutput()

This function returns all data available from the standard output of the process.

void start()

Starts the process set by program with the arguments given by arguments. This function returns immediately.

void terminate()

Attempts to terminate the process.

bool waitForFinished(int milliseconds)

Blocks until the process has finished and the finished() signal has been emitted, or until milliseconds have passed.

Returns true if the process finished; otherwise returns false (if the operation timed out, if an error occurred, or if this process is already finished).

If milliseconds is -1, this function will not time out.

bool waitForStarted(int milliseconds)

Blocks until the process has started and the started() signal has been emitted, or until milliseconds have passed.

Returns true if the process was started successfully; otherwise returns false (if the operation timed out or if an error occurred).

Signals

void errorOccurred(ProcessError error)

An error has occurred during execution. A human-readable version of the error may be obtained with errorString().

void finished()

This signal is emitted when the process finishes. exitCode is the exit code of the process (only valid for normal exits). After the process has finished, the buffers in QProcess are still intact. You can still read any data that the process may have written before it finished.

void started()

This signal is emitted by ProcessProbe when the process has started, and state is State::Running.

Project Item

class Project

A container item for multiple Testcase items.

Locations:document root
Nested items:Matrix, Testcase
Properties:name, references, workingDirectory

Detailed Description

A Project item represents a collection of of test cases. Test cases can be defined in two ways:

  1. in-line

    Usually used for a bunch of trivial test cases with only few lines or if complex test cases are instantiated multiple times with slightly different configuration.

    The test cases are executed in undefined order.

    Example in-line project:

    Project {
        name: "inline-project"
    
        Testcase {
            name: "trivial-1"
            function run() {
                // Qst.verify(...)
            }
        }
    
        // Assuming that ComplexTestcase.qml exists in the current
        // directory
        ComplexTestcase { name: "complex-1"; config: "something" }
        ComplexTestcase { name: "complex-2"; config: "something-else" }
    
    }
    
  2. as references

    Usually used in non-trivial projects. Test cases are defined in their own files and then referenced by the main project file. Any property prop attached to the project item is available in sub-items as project.prop.

    The execution order is defined by their occurrence order in the references item.

    Example references project:

    Project {
        name: "referencing-project"
        property string someProperty: "sometext"
    
        // someProperty is available in all test cases as
        // project.someProperty
        references: [
            "testcase1.qml",
            "testcase2.qml"
        ]
    }
    

Properties

string name
Default:empty string

Name of the project. This value does currently have no effect.

stringlist references
Default:empty list

A list of files containing test cases. Test cases are executed in the specified order. Paths are relative to the project file unless an absolute path is provided:

references : [
    "testcase-1.qml",         // Path relative to the project file
    "/path/to/testcase-2.qml" // Absolute file path
]
const string workingDirectory

Project-wide directory where all test cases are physically executed.

The default value is defined by --working-directory and cannot be changed from within QML.

SignalProbe Item

class SignalProbe

Watches signals from other items.

Inherits:Component
Properties:condition, count, signal
Methods:clear(), connect()
Signals:triggered()

Detailed Description

SignalProbe can be used to watch signals of other items. A typical use-case is a counter for asynchronous events:

import qst 1.0
import QtQml 2.0 as QtQml

Testcase {
    QtQml.Timer {
        id : timer
        interval: 5
        periodic: true
    }

    SignalProbe {
        id: probe
        signal: timer.triggered
    }

    function run() {
        Qst.compare(probe.count, 0, "Timer triggered too early");
        timer.start();
        Qst.wait(50);
        timer.stop();
        Qst.verify(probe.count >= 10, "Timer triggered only "
            + probe.count + " times");
    }

The following example shows, how SignalProbe can be used, to attach to a signal that is not directly accessible:

BaseTestcase.qml
import qst 1.0

Testcase {
    property var pinProbe : PinProbe {
        // properties
        // ...

        // Can attach directly to the valueChanged() signal.
        onValueChanged: {
            Qst.info("pin value is " + pinProbe.value)
        }
    }
}
ExtendedTestcase.qml
import qst 1.0

BaseTestcase {
    // Cannot attach directly to pinProbe's valueChanged() signal.
    // Use SignalProbe instead.
    SignalProbe {
        signal: pinProbe.valueChanged
        onTriggered: {
            Qst.info("pin value is " + pinProbe.value)
        }
    }
}

Properties

bool condition
Default:true

A guard for signal. When true, incoming signals increment the counter and emit triggered(). When false, the incoming signal is ignored.

int count

Counts how many times the signal has fired with respect to condition.

Signal signal

A signal of another item to attach to during the creation stage.

Methods

void clear()

Resets count to 0 but leaves the signal connection and the condition untouched.

void connect(signalHandler)

Connects the triggered() signal to a signalHandler of another item. This makes SignalProbe look like a QML signal for the other item.

Example:

DurationConstraint {
    from: SignalProbe { signal: someItem.someSignal }
    to: someOtherSignal
}

In this example, DurationConstraint tries to connect SignalProbe to itself by calling connect(). It doesn’t know that SignalProbe is an item and not a plain QML signal.

Signals

void triggered()

Emitted when signal is triggered while condition is true.

Testcase Item

class Testcase

Implements a test action.

Locations:Project, document root
Nested items:Component, Depends, Exports, Matrix
Enumerations:Result
Properties:dependencies, elapsedTime, name, result, workingDirectory
Methods:run(),
Signals:created(), destruction(), finished(), started()

Detailed Description

A Testcase component combines probes, constraints and other QML components into a single test case. It is executed as one atomic entity. Every test case must have a unique name throughout the project and must implement a run() method.

Example:

import qst 1.0

Testcase {
    name: "test-myprocess"

    ProcessProbe {
        id: process
        command: "/usr/bin/echo"
        arguments: [
            "Hello World"
        ]
    }

    function run() {
        process.start();
        process.waitForFinished(100);
        Qst.compare(process.readAllStandardOutput(), "Hello World");
        // Testcase will finish with result 'Pass'
    }
}

Enumerations

enum Result

The outcome of the test case execution. The default value after start is Unfinished. The result changes to Fail when the first evaluation statement fails or otherwise it is set to Pass when the run() method completes without any issue.

enumerator Unfinished

Default value after start.

enumerator Pass

The method run() has finished without any issue.

enumerator Fail

An error occured or one of the constraints has failed while executing run().

Properties

var dependencies

When the test case contains a Depends items, this property makes exported values for every dependency name or alias accessible. Data forwarded by Exports can be accessed in bindings and code. Dependencies are always attached in list form beause a test case might be represented by multiple jobs:

simple-exports.qml
        Depends {
            name: "A"
        }
        function run() {
            Qst.info("A was " + dependencies.A[0].result)
        }

This property is read-only.

uint64 elapsedTime

Time in milliseconds since the test case was started.

This property is updated on every read access and cannot be used as a binding.

string name

Identifier for this test case. This property must be a plain string and must be unique across the whole project.

The default value is an empty string.

Result result

The outcome of a test case run. The default value is Result::Unfinished.

const string workingDirectory

A unique directory where the current test case and child components may store files. The directory may be used for log files or as scratch pad and is always created on execution start.

The default value is project.workingDirectory + "/" + name and cannot be changed by the test case.

Methods

void run()

Contains the execution code and is called when the test case starts. It has to be implemented by the user. The run() method may contain several other blocking calls to methods and functions. It will return only for two reasons:

  1. All statements have been executed. result will be set to Result::Pass.
  2. An error has occurred or a constraint has failed and result has been set to Result::Fail. In that case, all remaining statements are aborted.

Signals

void created()

This signal is emitted after the destruction() signal of the previous Testcase and before started() of the current one. It is the QML way of implementing a constructor and can be used to initialize resources.

The signal is also attached to every Component as Testcase.created().

void destruction()

This signal is emitted before the Testcase component is physically destroyed and may be used to free up resources.

The signal is also attached to every Component as Testcase.destruction().

void finished()

This signal is emitted after the run() function has returned and may be used for final evaluation or cleaning up. By that time, result may not have been set, yet and thus, it is still allowed to call verification functions.

The signal is also attached to every Component as Testcase.finished().

void started()

This signal is emitted after created() and before run() is invoked. It may be used for starting concurrent activities.

The signal is also attached to every Component as Testcase.started().

UniflashProbe Item

class UniflashProbe

Flash programmer interface for Texas Instruments MCUs.

Inherits:Component
Properties:device, file, installPath programmer, serial
Methods:flash(), waitForFinished()
Signals:finished()

Detailed Description

UniflashProbe provides a convenient interface to Texas Instruments’ Uniflash. It can be used to read from and write to MCUs via a JTAG programmer.

The current state is experimental. Only XDS110 is supported. Since Uniflash doesn’t have a meaningful command line interface, XML config files are hacked together.

Example:

import qst 1.0
import ti 1.0

Testcase {

    UniflashProbe {
        id: uniflash

        installPath: "C:\ti\uniflash_4.2"
        serial: Xds.availableSerials()[0]
        device: "cc1352r1f3"
        file: test.workingDirectory + "/myApp.out"
    }

    void run() {
        uniflash.flash();
        uniflash.waitForFinished(10000);
    }
}

See also Xds.

Properties

string device

The exact MCU type, e.g. cc1310f128, cc1352r1f3. The case doesn’t matter.

string file

Path to a binary file to be read out or to be programmed. The file type has to be supported by Uniflash (.out, .bin, .hex).

string installPath

Installation directory of Uniflash.

string programmer
Default:XDS110

The JTAG programmer type.

string serial

The serial number of the programmer.

Methods

void flash()

Writes file to a device connected via programmer. Performs a board reset afterwards.

The method returns immediately and the programming process executes in background. When done, the finished() signal is raised.

bool waitForFinished(int milliseconds)

Blocks until the current operation has finished and the finished() signal has been emitted, or until milliseconds have passed.

Returns true if the process finished; otherwise returns false (if the operation timed out, if an error occurred, or if this process is already finished).

If milliseconds is -1, this function will not time out.

Signals

void finished()

This signal is emitted when an operation has finished.

See also flash().

ValueRangeConstraint Item

class ValueRangeConstraint

Checks whether a property is in a certain range.

Inherits:Component
Properties:enabled, evaluateOnFinished, evaluateOnValidation, maxValue minValue, valid, value

Detailed Description

ValueRangeConstraint checks whether value is within a range given by minValue and maxValue.

The constraint has two stages: validation and evaluation. Validation happens immediately after the value property has changed. Whether value is within the expected range, can be seen at the property valid.

During the evaluation stage, it is decided whether the test case is aborted. Evaluation can either happen immediately after validation (evaluateOnValidation is true) or just before the Testcase::finished() event (evaluateOnFinished is true). The enabled property switches measurement completely on and off.

Example for measuring the duration between two signals:

import qst 1.0
import QtQml 2.0 as QtQml

Testcase {

    QtQml.Timer {
        id: timer
        repeat: true
        interval: 123

        onTriggered: adc.start
    }

    AdcProbe {
        id: adc
        ioid: 23
    }

    ValueRangeConstraint {
        id: constraint
        minValue: 100
        maxValue: 300

        value: adc.value
    }

    function run() {
        timer.start
        Qst.wait(4000)
    }

Properties

bool enabled
Default:true

When false, the value property does not have any effect and the constraint is neither validated nor evaluated.

bool evaluateOnFinished
Default:false

If true, the constraint will be evaluated by Qst just before Testcase::finished().

See also evaluateOnValidation

bool evaluateOnValidation
Default:true

If true, the test case will fail immediately when validation fails. If false, then the constraint will not be evaluated immediately. Instead, it will be evaluated on Testcase::finished().

See also evaluateOnFinished

var maxValue
Default:undefined

Specifies the maximum allowed value.

See also minValue

var minValue
Default:undefined

Specifies the minimum allowed value.

See also maxValue

bool valid
Default:false

Reflects whether value is within the specified range.

var value
Default:undefined

The value to be validated. This property is usually bound to a property of another component. It may also be written manually if desired.

File Service

class File

Provides access to the file system.

Methods:exists()

Detailed Description

The File service provides information about the file system and limited access to file system operations.

Methods

bool exists(string filePath)

Returns true if filePath exists, otherwise false.

Qst Service

class Qst

Drives test case execution and provides information about the environment.

Properties:hostOs
Methods:compare(), error(), info(), verify(), wait()

Detailed Description

The Qst service is an integral part of Qst. It contains methods for test evaluation evaluation and provides information about test case execution and the host environment.

Qst is a singleton type and cannot be instantiated as a QML component.

Properties

const string hostOs

Returns the host operating system that Qst currently runs on.

Return value Operating systems
linux All kinds of Linux distributions on all platforms
windows Windows 7, 10

Methods

void compare(variant actual, variant expected, string message)

Compares an actual value to an expected value. If actual and expected are identical, execution continues. If not, a failure is recorded in the test log and the test won’t be executed further. The string message is optional. If not set, a default message is created.

Both values may be of any basic QML basic type. Arrays are compared by their containing values. Objects are compared by each property.

When compare() fails during test case execution, the current Testcase aborts immediately, the result is set to Testcase::Result::Fail and Qst proceeds with the next test case. When failing before the first test case starts, for instance in a Project item, Qst exits and no test case will be executed at all.

void error(string message, string file, int line)

Throws an error with message and aborts the current test case.

The parameters file and line are optional. If omitted, Qst takes those from the top of the caller stack.

void info(variant message)

Prints message in the test log output. The parameter message can be anything that converts implicitly into a string.

void verify(bool condition, string message)

Checks whether the condition is true or not. If it is true, execution continues. If not, a failure is recorded in the test log and the test won’t be executed further.

When verify() fails during test case execution, the current Testcase aborts immediately, the result is set to Testcase::Result::Fail and Qst proceeds with the next test case. When failing before the first test case starts, for instance in a Project item, Qst exits and no test case will be executed at all.

void wait(int ms)

Waits for ms milliseconds. While waiting, events will be processed and the test stays responsive.

This function should be only used inside Testcase::run(). It is not recommended to call it in binding expressions.

TextFile Service

class TextFile

Allows to read from and write into text files.

Enumerations:OpenMode
Methods:TextFile::TextFile(), atEndOfFile(), close(), readAll(), readLine(), truncate(), write(), writeLine()

Detailed Description

The TextFile service provides convenient access to text files in Javascript context. For instance, within Testcase::run():

function run() {
    // ...
    var file = new TextFile(test.workingDirectory + "/hello.txt",
            TextFile.WriteOnly, "UTF-8");
    file.write("Hello World");
    file.close();
    // ...
}

TextFile is to be used in Javascript context only and cannot be instantiated as a QML component.

Enumerations

enum OpenMode

Specified an access qualifier for the file. Options may be OR’ed togther:

new TextFile(path, TextFile.ReadWrite | TextFile.Append, "UTF-8");
enumerator Append

The file is opened for appending text. This is option may be combined with WriteOnly.

enumerator ReadOnly

Opens the file for read access only. Several instances may open the file in read-only mode at the same time.

enumerator ReadWrite

Opens the file for read and write access.

enumerator WriteOnly

Opens the file for write access only.

Methods

TextFile(string filePath, OpenMode mode, string codec)

Constructs a TextFile object and opens the file filePath with mode access permission and using a text codec specified by codec.

The filePath must be an absolute path. Options for codec are the same as for QTextCodec, for instance “UTF-8”, “UTF-16”, “ISO 8859-1” and others.

The default value for mode is OpenMode::ReadWrite. The default value for codec is “UTF-8”.

bool atEndOfFile()

Returns true if no more data can be read from the file, false otherwise.

void close()

Closes the file. It is recommended to always call this function as soon as you are finished with the file, in order to keep the number of in-flight file descriptors as low as possible.

string readAll()

Reads all data from the file and returns it.

string readLine()

Reads one line of text from the file and returns it. The returned string does not contain the newline characters.

void truncate()

Truncates the file. Sets the file size to zero and removes all content.

void write(string data)

Writes data into the file at the current position.

void writeLine(string data)

Writes data into the file at the current position and appends the newline character(s).

Xds Service

class Xds

Helper for XDS-based debugging interfaces.

Methods:availableSerials(), portFromSerial()

Detailed Description

The Xds service provides convenience functions for XDS-based debugging interfaces. It can be used, for instance, to identify connected debuggers.

The following example assumes that there is only a single XDS debugger connected and deduces it’s serial port identifier.

import qst 1.0
import ti 1.0

Project {

    property string launchpadPort: {
        var serials = Xds.availableSerials();
        Qst.compare(serials.length, 1,
            "Either no or too many probe boards connected");
        return Xds.portFromSerial(serials[0]);
    }

}

Xds is a singleton type and cannot be instantiated as a QML component.

Methods

stringlist availableSerials()

Returns the serial numbers of all connected XDS debuggers as an array of strings.

string portFromSerial(string serial)

Returns the port to which a given serial is connected to.

Language items

Name Description
Component Base type for various dynamic items.
Depends Describes dependencies between Testcase items.
Dimension Defines a value span within a Matrix.
Exports Forwards data to dependent Testcase items.
Matrix Replicates Testcase components with different property values.
Project Container item for multiple Testcase items.
Testcase Implements a test action.

Convenience items

Name Description
DurationConstraint Checks the time between two signal occurrences.
PinProbe Represents a digital IO pin on the launchpad probe board.
SignalProbe Watches signals from other items.
ProcessProbe Starts and watches processes.
UniflashProbe Flash programmer for Texas Instruments MCUs.
ValueRangeConstraint Checks whether a property is in a certain range.

Services

Name Description
File Provides access to the file system.
Qst Helper functions for test execution.
TextFile Reads from and writes into text files.
Xds Represents XDS-based debugging interfaces.