I Guess I Test Now

My favorite joke, or truth, is “We’ll test in Production.” Which is great when things work. I added a lot more features to ThiefMD. My test approach was “Hands on Functional Testing.” Which worked well until I tried to do a release blog post, and the images weren’t there.

So today, I learned how to enable GitHub Actions.

Hopefully it’ll prevent me from breaking anything major.

Downloading Strange Things on the Internet to Stranger’s Computers

One of the issues I ran into was GitHub Workflows run Ubuntu 20.04. I needed libhandy-1-dev, which isn’t included by default.

There’s some random libhandy-1 ppa for Focal, which I decided to use. Luckily, it’s on GitHub’s computers, so I don’t need to worry about anything bad happening on my laptop 😅. I also stole some of the Workflow from vala-langauge-server’s daily integration.

For my Vala project, I wound up with:

name: ThiefDaily
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Add vala next
        run: sudo add-apt-repository ppa:vala-team/daily
      - name: Add libhandy-1 for focal
        run: sudo add-apt-repository ppa:apandada1/libhandy-1
      - name: Update Ubuntu
        run: sudo apt-get update
      - name: Install build essentials
        run: sudo apt-get install build-essential meson ninja-build valac cmake libgtkspell3-3-dev libwebkit2gtk-4.0-dev libmarkdown2-dev libxml2-dev libclutter-1.0-dev libarchive-dev libgtk-3-dev libgee-0.8-dev libgtksourceview-4-dev libsecret-1-dev libhandy-1-dev
      - name: Init submodules
        run: git submodule init
      - name: Update submodules
        run: git submodule update --remote --recursive
      - name: Setup Build
        run: meson build
      - name: Configure build
        run: meson configure -Dbuild_tests=true build
      - name: Run Build
        run: ninja -C build
      - name: Test
        run: ./build/tests/tests

The first steps are adding package repositories and installing build requirements. Init submodules & Update submodules downloads source code dependencies.

Test is where the magic happens. This workflow lets me know when things aren’t working:

Test & Build Status

Testing with GLib.Test?

I couldn’t find anything too recent on GLib.Test testing. GNOME Documentation simplifies it to add_func and assert. I could make this work.

I created a main function for running the tests.

public class ThiefTests {
    public static int main (string[] args) {
        Test.init (ref args);
        new ImageExtractionTests ();
        new MarkdownTests ();
        new FileManagerTests ();
        return Test.run ();
    }
}

ImageExtractionTests monitor what I broke. It’s all a bunch of complicated Regexes, so they’re worth monitoring still.

Test.init is required for setting up the test environment. Each new BoringTests(); adds a set of tests to run. Test.run () runs all the tests added and returns a status code for pass or fail.

For example, the MarkdownTests (which don’t test Markdown) look like:

using ThiefMD;
using ThiefMD.Controllers;

public class MarkdownTests {
    public MarkdownTests () {
        Test.add_func ("/thiefmd/file_extensions", () => {
            assert (is_fountain ("screenplay.fou"));
            assert (is_fountain ("screenplay.fountain"));
            assert (is_fountain ("screenplay.spmd"));
            assert (!is_fountain ("screenplay.markdown"));
            assert (!is_fountain ("screenplay.fountain.markdown"));
            assert (!is_fountain ("screenplay.docx"));
            assert (!is_fountain ("screenplay.bib"));
        });

        Test.add_func ("/thiefmd/titles", () => {
            assert (make_title ("this_cool_cat") == "This Cool Cat");
            assert (make_title ("this-cool_cat") == "This Cool Cat");
            assert (make_title ("this_cool-cat") == "This Cool Cat");
            assert (make_title ("this cool-cat") == "This Cool Cat");
            assert (make_title ("this_cool cat") == "This Cool Cat");
        });

        Test.add_func ("/thiefmd/find_file", () => {
            assert (Pandoc.find_file ("README.md", Environment.get_current_dir ()) != "");
            assert (Pandoc.find_file ("README.md", Environment.get_current_dir ()) != "README.md");
        });
    }
}

I can call Test.add_func as many times as I want. The first string has to be unique. assert will fail the tests if the condition is false. If all the asserts have true conditions, the tests are considered passed.

I added tests for resolving absolutio reference paths, and creating the list of images to upload. I also sprinkled in a few tests for other critical functionality.

So hopefully, I don’t break anything major again.