Saturday 30 December 2017

TrafficControl: Locking Tracks for Trains - Code

Preventing trains to collide is an essential of any traffic controller. In this blog post, I'll implement some basic functionality for that purpose.

I'll use a simplistic model with two boolean variables: lockedUpStream (end station locked) and lockedDownStream (start station locked) with corresponding get and set classes.

When the train is in readyState (in a station), it will try to find a suitable track to the target station in Station::findLeavingTrackIndexToStation(int targetStationID).

If the train finds a suitable track and enters it, it will set a lock on the track:
  • When a train enters a track in upstream direction, the lockedDownStream will be set to true.
  • When a train enters a track in downstream  direction, the lockedUpStream will be set to true (see above). This happens in track::findLeavingTrackIndexToStation.
  • When the last train leaves track in upstream direction, the lockedDownStream will be set to false.
  • When the last train leaves track in downstream direction, the lockedUpStream will be set to false.
If all suitable tracks are locked, the train will wait one second and search for tracks again. 

As a safeguard, the track will also consider the locks when adding a train:

The locks are reset only if there is no train on the track.

The next blog post will cover tests and visualisation of track locks.

Future improvements:
For a certain time after a train enters the track, the track should be marked as red and no trains should be able to enter from any direction.

Saturday 23 December 2017

TrafficControl: Making User Interface Flexible with DockWidgets

Some readers may have seen that the user interface has a new look. Now, the user can select which widgets should be visible at run-time, how big they should be and where in the program they should be.

The user interface is designed in the file TrafficControl.ui, that is based on XML. That file contains the different widgets that makes up the user interface. 

When compiling, TrafficControl.ui generates a corresponding header file that  is called from the program (trafficControl.cpp/h):
The file ui_trafficControl.h is generated at runtime from the file trafficControl.ui
I've added qDockWidgets to the form that contains the elements. A qDockWidget is basically a container that can dock to different borders of the applications interface. The user interface assigns some space on the form, depending on the size of the contents, other widgets and the user's decisions.



A qDockWidget can be closed (set to invisible) and floating (presented in a separate window) if the user wants to. A list of the qDockWidgets is shown if the user right-clicks on the title for a qDockWidget.


This is needed as my program grows and there will be much more information to present to the user.

I've recently learnt how to use qDockWidgets and I'll explore more of its abilities in a future blog post. 

Future work: 
Add a panel of pushButtons, one for each qDockWidget that is available in the program. The buttons should have icons that describe the contents, for example Map, Train List, Basic Controls, Log window...

Saturday 16 December 2017

TrafficControl: Testing Asserts

Asserts are used to ensure that events that should never happen will never happen.

I've created a test case, where the program will try to add the same train to a station twice. If that happens, it would be a sign that the program has totally lost control of the network.
The program adds a train to a station. After that, it tries to add the same train to the station again. The expected result shall be an Assert.
When the code tries to add the same train again, the code asserts:

After this dialog, the test sequence stops and the remaining test cases are not run.

I found a workaround in a StackOverflow thread. A message handler will acknowledge the Assert message in the test case and the test suite can continue:
A message handler is specified before the expected Assert. It acknowledges the assert, without crashing the test.




Saturday 9 December 2017

TrafficControl: Opposite Direction TDD Case (2)

After fixing the first issue with trains that can't find adjacent stations, a new issue has been seen.



The train arrives to Gärsnäs and is supposed to enter the track Sim-GarW at end position (12000). It should move to position 0 and enter Simrishamn. However, it enters the track at start position (Simrishamn) and moves towards Gärsnäs. 


The train state model needs to handle the reversed scenario. A bool reversedTraffic with a get/set method is added to the track object. 

I made changes in the methods train::readyToRunning, train::runningState and train::runningToOpening. 

The train needs to consider its direction (normal or reversed) when entering a track.
train::runningState introduces a virtual position, that is

  • virtualPosition = position, if train isn't travelling in reversed direction,
  • virtualPosition = track length - position, if train is travelling in reversed direction


With these changes, the train is able to travel in reversed direction.

A crash was found for train::setTrackPosition(0). When it is updating the position, the method track::getCoordinatesFromPosition asserted if the position was 0, since it was trying to access coordinates at index -1.

Saturday 2 December 2017

TrafficControl: Opposite Direction TDD Case (1)

One big stub in trafficControl is that it currently only allows trains to travel on tracks in the intended direction (position 0 up to the end).

To enable trains to move in reversed directions, I will follow the Test-Driven-Development method.

The first iteration is to test a train on a station with one leaving reversed track. The track leaves Simrishamn (start) and arrives to Gärsnäs (end). A train in Gärsnäs that shall go to Simrishamn should find the track and travel in reverse on it to Simrishamn.


In this video, the train was supposed to travel back from Gärsnäs to Simrishamn, but that didn't happen.

The issue is that the method findLeavingTrackIndexToStation only searches for connected tracks where the end station is matching target station. For reversed tracks, the start station will match the target station. No suitable track is found and the function returns UNDEFINED.

To fix the issue, the program will search for a leaving track in the reversed direction in case it doesn't find a track in the ordinary direction.

A corresponding test case has been added:

With this change, the program still fails. After leaving Gärsnäs, the train enters the track near Simrishamn and travels to Gärsnäs. I'll  solve that in the next blog post.

Saturday 25 November 2017

TrafficControl: Time Needed for Reading Network File and a Real Bug

In a previous blog post, I mentioned that it took more time to load a network file. The reason for the delay was that I compiled the program in debug mode. After compiling in debug mode, reading a large network file took some 20-25 seconds. The same operation takes 5 seconds on a release build. However, I'll need a test to benchmark such operations.

A real bug was found when defining an unit test case for the train load passenger method.

For a train with a capacity of 100, the test adds four passengers and later 100 passengers. The expected result is that four passengers will be denied.
The test tries to load more passengers than the train has capacity for. The expected verdict is that the train will be full and that the load method will return the number of passengers that were denied entry to the train.

The load function didn't consider the train capacity or the number of present passengers. This was fixed:

After the fix, the new testcase is passing.

The passenger handling is stubbed. In the future, the program needs to make the passengers plan their journey.

Saturday 18 November 2017

Trains: High Speed Trains... in Sweden???

No one who is reading my blog can question my passion for trains. A part of me would be very enthusiastic about entering a Thalys-like train at Malmö Central, reaching Stockholm two and a half hours later. Another part of me is looking at the numbers.

In two previous blog posts, I've seen that the population is much smaller for Sweden, compared with the lines in France, Germany, Spain and Japan.

Trafikverket (The Swedish Transport Administration) has made an economical assessment of the proposed high speed rail lines. That report saw significant advantages with high speed trains:
  • Increased capacity in the entire rail system, including existing lines.
  • Cargo trains won't slow down passenger trains.
  • Great reductions in travel time (36-64% reduction between Swedish towns along the line)
The value of the benefits were estimated to 150 billion SEK. However, the costs were estimated to be some 409 billion SEK. The return of investment would be 40%, a very poor prospect.

As the rail system in Sweden is already mature, the benefits of such a big project will smaller than the costs and the conclusion from the report is that high speed rail in Sweden will be too expensive.

I agree with that report. Such a project would starve out other investments that are necessary. The money should be used to build on the existing rail network, resolve bottle-necks and maintain the lines properly. High speed rail will starve out other, more efficient improvements.

Saturday 11 November 2017

TrafficControl: Crash When Using a Network Without Coordinates

In a previous blog post, I've seen that the program asserts when using a network without coordinates.

The assert is trigged when the train is in state "RUNNING":

After adding prints, I've seen that the issue comes when the train is in Train::runningState. The train tries to set the new position on the track using this->setTrackPosition.

The train is trying to get coordinates for a position on the track. But as the track has no coordinates, the code asserts.

The program is trying to act on the coordinateList that doesn't exist,
One solution can be to check if the coordinateList has length = 0. If that is the case, return 0. Also, the calling program should check if the track has coordinates. I'll add a boolean hasCoordinates to Track, and a corresponding get method.

The fix for train::setTrackPosition() is:

Saturday 4 November 2017

Trains: High Speed Trains... to Lyon???

In the first blog post about the planned 320 km/h high speed rail in Sweden, I calculated the population along the line from Lund to Järna (Malmö/Copenhagen to Stockholm).

Image credit: Wikimedia Commons
As of 2017, there are only four high speed lines of 320 km/h: Madrid to Barcelona, Paris (eastbound and westbound) and Dijon to Basel.

The following table compares some existing lines with the planned Swedish line. The populations are calculated within a 10 km and a 25 km radius from the stations. For the Swedish line, I exclude and include København in the calculations.

Start End Speed Stations Length Pop 10 km Pop 25 km
Malmö Stockholm 320 km/h 12 460 km 1,6 M/2,5 M 3 M/4,5 M
Paris Lyon 300 km/h 4 427 km 4,3 M 10 M
Paris Strasbourg 320 km/h 5 409 km 4,8 M 10 M
Madrid Barcelona 320 km/h 8 600 km 5,7 M 12 M
Tokyo Niigata 320 km/h 12/5 270 km 8,5 M 26 M

I also added the Japanese Joetshu Shinkanshen line, one of the smaller lines in the Shinksanshen network.

The proposed Swedish line will serve a much smaller population than the other lines. Also, that line has 12 stations, that will make the trains slower. One stop will take some five minutes, according to the time tables for the French/Spanish lines.

For the Paris/Strasbourg line, there are 17 departures per day in each direction. 13 of them doesn't stop between Paris and Strasbourg. A similar tradeoff will be necessary for the train operator in Sweden: Either stop at many stops, using the stations that are built but also making the train slower, or travel directly between Malmö/Copenhagen and Stockholm, passing several important stations without stopping.

Intermediate conclusion: 
Sweden has a much smaller population density and smaller cities than the European countries. The demand for travels will be much smaller than for the existing lines.

Saturday 28 October 2017

TrafficControl: Protecting the Code With Asserts

Asserts are checking whether a condition is met. If the condition isn't met, the program will throw an error message and break. They are used to ensure that something never ever happens in the program (asserts are only used when debug flag is enabled).

TrafficControl is based on three lists of objects (trainList, trackList and stationList), The elements in those lists are called directly, so the entire logic of the program is based on a direct relation between the ID's of the elements and their position in the lists. Removing elements will not be allowed.

For example: Add three trains to the network. The result is a trainList:
trainList.at(0) has ID: 0
trainList.at(1) has ID: 1
trainList.at(2) has ID: 2
totalNbrOfTrains = 3

Remove the second train and reduce the totalNbrOfTrains:
trainList.at(0) has ID: 0
trainList.at(1) has ID: 2 
totalNbrOfTrains = 2

Now, there is a mismatch between the ID for the second train in the trainList and its position. 

To detect when it happens, I've added an assert that fires if there is such a mismatch for the last items in the lists.
The trainList must always be empty, or its last element' ID must match the length of the list.
If the assert fails, a dialog pops up and the user can decide whether to retry, abort or ignore the error.
The button are using the language specified by the operating system. In this case, they are: Abort, Retry and Ignore.
As a side note, I've discovered two bugs that I need to fix. I'll address the issues in future blog posts:

The program asserts when using a network without coordinates. It happens when the train is running on tracks and is trying to calculate its coordinates.

Solution: Check if the train and track has coordinates when updating the position for a train on the track.

The program is slower when importing network file. Before refactoring it, it took the program 5 seconds to scan the file. Now, it takes 25 seconds.

Solution: Scan all lines and send as a stringlist to new NetworkControl::parseNetworkCommands(QStringList). 

Saturday 21 October 2017

Trains: High Speed Trains... to Tranås???

Swedish railways suffer from limited capacity and maintenance lagging behind. There are negotiations regarding some future high speed rail lines, that would connect the biggest population centres in Sweden in the future (Stockholm, Göteborg and Malmö/København). The speed is planned to be 320 km/h.

There is some debate whether the project is a good idea, and I'll discuss my opinion in two blog posts. As a Malmö resident, I'll focus on the line between Malmö and Stockholm.

Let's start with demography and geography.

I'll compare the proposed line with some existing lines with respect to length, number of stops and population near the stations. I'll use an online tool to calculate the population in a 10 km radius and in a 25 km radius from the station.

The proposed line between Malmö and Stockholm (high speed between Lund and Järna) will be 550 km (approximately 500 km high speed rail). There will be nine stops between Malmö and Stockholm and the time will be 2½h according to Europakorridoren.

Excluding København (60 km from Lund), the total population of all towns served by the line will be 1.6 M/ 3 M. Including København, the population of all towns will be 2.5 M/ 4.5 M. Some of the smaller stations include Tranås and Vagnhärad with populations of 10 to 20 thousand people.

A future blog post will compare the Swedish project with some existing European high speed lines with similar speeds.

Saturday 14 October 2017

TrafficControl: Using Test Fixtures for Unit Tests

For many unit tests, there are some similarities that can be used to reduce some redundant code.

For example, the datamodels for the trafficDataModels (for train, station and track), a pointer to the QML part of the program and the networkControl object.

Google Test offers test fixtures, that makes it possible to setup the same parameters for a set of tests. The test code will be cleaner and each test case will have (more or less) the same setup.


A test fixture is a class where some pointers to some objects are defined.

In SetUp, the data models are defined, a null pointer is set for the QML part and a networkControl object is created.

The TearDown method will free up the allocated memory and clean up the test environment.


The test case is then defined using TEST_F, where the appendix indicates that a test fixture will be used. The test case is networkTest, that was defined above.

In the test case, the networkControl, the needed elements are already defined. The cleanup will be done automatically by TearDown when the test is done.

The concept isn't water-proof, however. The traffic elements (for example trains) has a static int variable to count the total number of trains/stations/tracks. I didn't reset that parameter initially, which caused some test cases to fail. 
  1. Before the first test with the test fixture, that parameter was 0. 
  2. After the first test case, where a train was created, the parameter was set to 1. 
  3. When deleting the train object (called in the networkControl destructor), the static parameter wasn't affected.
  4. In the second test case, the totalNbrOfTrains was 1, but it should have been 0. This caused the test to fail since the test checked the totalNbrOfTrains parameter. 

To fix that issue, the totalNbrOfTrains is set to 0 in the destructor for networkControl.

Saturday 7 October 2017

Trains: Double Decker Trains Above Öresund

On June, this year, the committee of public transportation of Region Skåne decided to introduce double decker trains on one of the busiests train line in the Öresund area (Copenhagen-Malmö-Lund-Helsingborg).

This is needed to increase the capacity on the line between Copenhagen and Malmö, that is very used by commuters and people going to and from Copenhagen airport, the busiest airport in Scandinavia.

Currently, a maximum of three trains (three 78.9 meter trains) can be connected and used, with a total capacity of some 600 passengers. The limit is the platform length of the sub-terranean station Triangeln in Malmö.

With the new trains, the capacity will increase to 800 to 900 passengers per train.

It is not yet decided which type of trains will be used but one likely candidate is Alstom Coradia Duplex, that is already in use in Sweden. Comparing that model with the current Öresundståg (X31), it seems that the capacity in terms of seats per meter is almost the same.

Öresundståg (X31) has a length of 78,9 meters and a capacity of 229 seats (2.9 passengers per meter).
Alstom Coradia Duplex (X40) comes in different lengths. The five car option has a length of 134 meters and a capacity of 570 seats (4,2 passengers per meter). The seven car option has a length of 186,7 meters and a capacity of 810 seats (4,33 passengers per meter).

The new trains are planned to be in use from 2019.

Saturday 30 September 2017

TrafficControl: Refactoring trafficControl Class

This week-end, I've refactored the code to make it more testable and more agnostic.

The class trafficControl contains currently both GUI elements and logic for defining the traffic networks. Having both user interface and program logic in the same class will make automated testing difficult, and I need to refactor the code so that the user interface is separated from the logic.

The current structure of the program is:
  • main.cpp includes 
    • trafficControl.h, which includes
      • ui_trafficControl.h (this is autogenerated at run-time which causes problems when unit testing)
      • tcTrack
      • tcTrain
      • tcStation
      • trafficDataModel
      • trafficClock
I want to have a slightly different structure where the ui and the traffic logic is separated.
  • main.cpp includes
    • trafficControl which includes
      • ui_trafficControl.h (autogenerated)
      • tcNetworkControl which includes
        • tcTrack
        • tcTrain
        • tcStation
        • trafficDataModel
        • trafficClock
Steps taken for refactoring:
1. Remove ui references in tcTrack/tcTrain/tcStation/trafficDataModel/TrafficClock
2. Create tcNetworkControl files
3. Initiate tcNetworkControl
3. Move everything except ui elements to tcNetworkControl and update the references to it.
4 Copy reference to station/train/trackListModel to tcNetworkControl and also handleQMLObject
5. Ensure that the program works both when testing and in normal mode.

I also made some changes to the code that imports a file with network commands. Previously, that code opened a file, scanned it for all lines and interpreted them to commands. The new code scans a file, and parses the lines to another method in networkControl. With this change, I'll be able to define the network from other sources, such as test case and user input at runtime.

Monday 25 September 2017

TrafficControl: Integrating Google Test Into TrafficControl

After some struggle, I was finally successful with integrating Google Test into TrafficControl.

The steps are similar to the QtTest Integration blog post and the previous blog post:

I add two files to the "test" folder:
  • mainTest.cpp that is calling the test code and
  •  tst_tcUnitTests.h, where I have the test code.
In the pro file, I replace the QtTest directives with Google Test directives:

The mainTest.cpp is identical to the one in the Google Test example. The results can be seen below.

With Google Test, it is easy to sort test cases into different categories. That will be necessary as the number of test cases grow.

In the near future, I'll port the existing QtTest test cases to Google Test and implement the other test cases. I'll keep the existing QtTest files for now, even if I won't use them.

Wednesday 20 September 2017

TrafficControl: Analysing a Simple Google Test Project

To understand Google Test, I created a sample test application using Qt 5.9, that is using Microsoft Visual C 2015 and Google Test.



As for other Qt  projects, it is a good idea to start looking at the pro file:
+= means add module to project when compiling. -= means remove module.
The qt part is removed for this particular project. I assume that it is since no Qt code is to be tested in this project. It is still possible to compile and test when keeping qt in the project (by commenting out the removal clause on line 7). The same is for the app_bundle tag on line 5.

Google Test is added on the first line, using include statement. Let's have a look at the gtest_dependency.pri file.

The syntax is described in the Qt documentation
The syntax is descibedInitially, there are some checks for whether there is a defined GOOGLETEST_DIR on the computer. If not, the compiler will throw an error message to the build console. If there is such a directory, the test project will be compiled for GTest/GMock.

The test cases are listed in tst_firstgoogletestcase.h as separate functions. The tests are sorted into test cases and test sets, making it possible to have several test sets. This will be useful for me, since I want to sort the test cases in TrafficControl.

The cpp main file initiates the test suite.

In the next blog post, I'll try to import the test cases into the TrafficControl project.



Friday 15 September 2017

TrafficControl: Testing, Bug in Station Coordinate Check

When developing the unit tests, I'll only cover the interesting ones (the ones that exposes bugs in my code) in the blog.

One such test case is stationTest.invalidFloatCoordinatesAtCreation. 

The test case creates a station at 105°N, 13°E, and also another station at 55°N, 213°E. When testing, the result is:
The first coordinate is too big, but is parsed to the station anyways. In the second case, the coordinates are wrongly accepted.
The code is checking only the latitude for correct values. It also doesn't set the coordinate to 0, if the values are bad.

The new code that is passing is:

I also added a check in station::getLatitude and getLongitude, so that it returns 0 if hasCoordinates is false.

I'll investigate if I can define a more generic algorithm for validating coordinates, since that will be usefulwhen validating tracks in the future.

The location of 0 degrees N, 0 degrees E. It is tempting to let 0/0 indicate that there is no such station, but such assumptions can be dangerous.



When defining the test case, a part of me wanted to skip the check for coordinatues. That feeling is a very good reason to out extra focus on that test. 

Sunday 10 September 2017

Old Tracks: Future Trail over Hallandsåsen

I've discussed trails along old tracks in two blog posts, one for a line near Malmö and one for the High Line in Manhattan. A new trail is planned for the old tracks over Hallandsåsen in the northern parts of Skåne, Sweden.



The old tracks over Hallandsås were ready 1885, as a part of the line between Helsingborg and Halmstad on the Swedish west coast. The area is very beautiful with an astonoshing view of Båstad and the bay of Laholm just before entering the railway station of Båstad.

It was aso a very difficult track for the trains for some reasons. The incline is quite high, so some cargo trains needed to accelerate before approaching the ridge in order to have a chance to cross it. At some periods, stand-by locomotives were waiting in Förslöv and Båstad to give extra support for the trains.

During fall, wet leaves made the tracks very slippery, making it even harder to pass Hallandsåsen. The railway was a single track line with very limited top speed and a meeting point in Grevie, so a very limited number of trains could pass every hour.

It became more important to resolve that bottle-neck when the traffic volumes increased between Malmö and Göteborg, and a tunnel under the ridge was built between 1991 and 2015. The project became much more expensive and complicated than forecasted.

The first leg of the trail is planned to be ready in 2018 and it will be possible to visit it by bike, foot or riding a horse. 

An article (in Swedish) about the railway history on Bjärehalvön can be found here.

Tuesday 5 September 2017

TrafficControl: Testing Google Test

Now when I got QtTest working, I want to investigate how to use Google Test.

Google Test can be used with Qt Creator, and I need to find out how to use that for two reasons:

  1. Google Test might be more powerful with respect to functions,
  2. Google Test is more well-known than Qt Test and I will probably use it in future projects.

It's pretty simple to create a stand-alone Google Test application:

  1. First, I cloned cloning the GoogleTest repo using "git clone https://github.com/google/googletest.git", 
  2. After that, I created a Google Test project according to the Qt documentation.
  3. After compiling, the test is verifying and asserting the value of 0 and 1.


In the next blog post, I'll look into the files of the project and try to add test cases, and also to include Google test into TrafficControl.

Thursday 31 August 2017

TrafficControl: Test Driven Development

Test Driven Development (TDD) is a process for software development is based on automated tests to develop new functionality.

TDD is based on five steps:
  1. Define an automated test and add it to the test sequence. Ideally, that test case should make the target code fail.
  2. Run the test sequence and see that the target code fails on the new test. 
  3. Fix the target code so that the new test case is passing. At this stage, the fix should be "quick and dirty".
  4. Re-run the test sequence.
  5. Refactor the code. Here, the fix in step 3 should be refactored.
In TrafficControl, I'll show an example of unit testing. The tcStation object can add and remove waiting passengers. One kind of tcStation is a Junction, that shouldn't be able to add and remove passengers. So, one new test is to check whether a Junction can add passengers.

1. Add a test: station_junctionHasNoPassengersAfterAddingTen()

2. Run the test sequence. The target code failed the test as the junction added ten passengers,

3. Fix the target code. I need to both add a method tcStation::isJunction(), and also modify the method tcStation::changeNbrOfPassengers().
 4. Re-run the test sequence. Now, the program doesn't change the number of passengers if the station is a junction, as expected.
5. Refactor (Not needed in this particular case)

As with other tools, it is important to be pragmatic and understand when TDD is useful and when it should be avoided. Having a dogmatic view on different tools/methods/frameworks will lead to a lot of time spent on suboptimal solutions.

"You may have the best hammer but not all problems are nails." In some cases "happy testing" / happy coding is necessary. User interface development, for example may be difficult to use with TDD. The TDD process doesn't encourage long-term design considerations, which is crucial for bigger projects.

Saturday 26 August 2017

TrafficControl: The First Unit Tests - tcStation

The first unit tests for TrafficControl address one single station object. This will be a brain-storming session, where I add a lot of test cases without implementing them. In those cases, I have commented out the test cases that are yet to be implemented.

The commented test cases are not implemented yet. I also add a short description of the test cases.

When creating one station object, the default values must be verified:
  • Is the station empty initially, both with regard to the number of trains and passengers?
  • What happens if invalid coordinates are sent to the constructor of station? If the coordinates are float values, but too big (-100.0, 199)?
  • What happens if the station name is already taken?
When creating test cases, I sometimes realise that I need to extend the existing target code to be more testable and observable. That's the very purpose of verification: identifying ways to improve the code.

The test case "station_noCoordinatesAtCreation()" reveals that it useful to add a boolean "hasCoordinates" and a method "tcStation::hasCoordinates();".

The next blog post will introduce Test-Driven Development and show an example of using that methodology.

Monday 21 August 2017

TrafficControl: Integrating QtTest Into TrafficControl

After some hours looking at official Qt Documentation, internet forum posts and blogs, I found out how to add Qt Tests to the project, and it is quite easy!

A separate folder named test was created for the test code, where I added a C++ file with the name "tst_traffic.cpp".


The project file gets a debug clause (build commands that are only applied for debug builds):
When running QMake the next time for debug builds, the file main.cpp will be removed from sources. Instead the file tst_traffic.cpp will be added to the sources. Also, the testlib is loaded.

The test cases are listed as private slots and implemented as functions. The QVERIFY macro is used for the verdict.



The test report is shown below.

The next blog posts will cover the new test cases. The target code will be developed in parallel, since I need to change it to be more testable. I'll also use Test Driven Development, which I'll describe in the next blog post.