merged heads sync
authorKrista 'DarthMama' Bennett <krista@pep.foundation>
Mon, 25 Nov 2019 11:00:36 +0100
branchsync
changeset 4220fa9a1793f6e0
parent 4219 5b85e2e8bb70
parent 4217 738d4cbc5af5
child 4221 9016d0c7b5c6
merged heads
test/src/test_util.cc
     1.1 --- a/src/pgp_sequoia.c	Wed Nov 20 16:11:25 2019 +0100
     1.2 +++ b/src/pgp_sequoia.c	Mon Nov 25 11:00:36 2019 +0100
     1.3 @@ -173,17 +173,15 @@
     1.4      pgp_packet_t a_userid = pgp_user_id_from_raw (a, a_len);
     1.5      pgp_packet_t b_userid = pgp_user_id_from_raw (b, b_len);
     1.6  
     1.7 -    T("(%.*s, %.*s)", a_len, (const char *) a, b_len, (const char *) b);
     1.8 -
     1.9 -    char *a_address = NULL;
    1.10 -    pgp_user_id_address_normalized(NULL, a_userid, &a_address);
    1.11 -    if (!a_address)
    1.12 -        pgp_user_id_other(NULL, a_userid, &a_address);
    1.13 -
    1.14 -    char *b_address = NULL;
    1.15 -    pgp_user_id_address_normalized(NULL, b_userid, &b_address);
    1.16 -    if (!b_address)
    1.17 -        pgp_user_id_other(NULL, b_userid, &b_address);
    1.18 +    char *a_email = NULL;
    1.19 +    pgp_user_id_email_normalized(NULL, a_userid, &a_email);
    1.20 +    if (!a_email)
    1.21 +        pgp_user_id_uri(NULL, a_userid, &a_email);
    1.22 +
    1.23 +    char *b_email = NULL;
    1.24 +    pgp_user_id_email_normalized(NULL, b_userid, &b_email);
    1.25 +    if (!b_email)
    1.26 +        pgp_user_id_uri(NULL, b_userid, &b_email);
    1.27  
    1.28      pgp_packet_free(a_userid);
    1.29      pgp_packet_free(b_userid);
    1.30 @@ -192,24 +190,24 @@
    1.31      // first string is less than, equal to, or greater than the
    1.32      // second, respectively.
    1.33      int result;
    1.34 -    if (!a_address && !b_address)
    1.35 +    if (!a_email && !b_email)
    1.36          result = 0;
    1.37 -    else if (!a_address)
    1.38 +    else if (!a_email)
    1.39          result = -1;
    1.40 -    else if (!b_address)
    1.41 +    else if (!b_email)
    1.42          result = 1;
    1.43      else
    1.44 -        result = strcmp(a_address, b_address);
    1.45 +        result = strcmp(a_email, b_email);
    1.46  
    1.47      if (true) {
    1.48          T("'%s' %s '%s'",
    1.49 -          a_address,
    1.50 +          a_email,
    1.51            result == 0 ? "==" : result < 0 ? "<" : ">",
    1.52 -          b_address);
    1.53 +          b_email);
    1.54      }
    1.55  
    1.56 -    free(a_address);
    1.57 -    free(b_address);
    1.58 +    free(a_email);
    1.59 +    free(b_email);
    1.60  
    1.61      return result;
    1.62  }
    1.63 @@ -244,15 +242,17 @@
    1.64  
    1.65      // Create the DB and initialize it.
    1.66      size_t path_size = strlen(home_env) + sizeof(PEP_KEYS_PATH);
    1.67 -    char *path = (char *) calloc(1, path_size);
    1.68 +    char *path = (char *) calloc(path_size, 1);
    1.69      assert(path);
    1.70      if (!path)
    1.71          ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
    1.72  
    1.73  	int r = snprintf(path, path_size, "%s" PEP_KEYS_PATH, home_env);
    1.74      assert(r >= 0 && r < path_size);
    1.75 -    if (r < 0)
    1.76 +    if (r < 0) {
    1.77 +        free(path);
    1.78          ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "snprintf");
    1.79 +    }
    1.80  
    1.81      int sqlite_result;
    1.82      sqlite_result = sqlite3_open_v2(path,
    1.83 @@ -790,7 +790,7 @@
    1.84      pgp_tsk_t tsk = pgp_tpk_as_tsk(tpk);
    1.85      pgp_status = pgp_tsk_serialize(&err, tsk, writer);
    1.86      pgp_tsk_free(tsk);
    1.87 -    //pgp_writer_free(writer);
    1.88 +    pgp_writer_free(writer);
    1.89      if (pgp_status != 0)
    1.90          ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Serializing TPK");
    1.91  
    1.92 @@ -856,7 +856,12 @@
    1.93  
    1.94          pgp_packet_t userid = pgp_user_id_new (user_id_value);
    1.95          pgp_user_id_name(NULL, userid, &name);
    1.96 -        pgp_user_id_address_or_other(NULL, userid, &email);
    1.97 +        // Try to get the normalized address.
    1.98 +        pgp_user_id_email_normalized(NULL, userid, &email);
    1.99 +        if (! email)
   1.100 +            // Ok, it's not a proper RFC 2822 name-addr.  Perhaps it
   1.101 +            // is a URI.
   1.102 +            pgp_user_id_uri(NULL, userid, &email);
   1.103          pgp_packet_free(userid);
   1.104          free(user_id_value);
   1.105  
   1.106 @@ -1238,7 +1243,7 @@
   1.107                          // Make sure the TPK is not revoked, it's
   1.108                          // creation time is <= now, and it hasn't
   1.109                          // expired.
   1.110 -                        pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
   1.111 +                        pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
   1.112                          bool revoked = (pgp_revocation_status_variant(rs)
   1.113                                          == PGP_REVOCATION_STATUS_REVOKED);
   1.114                          pgp_revocation_status_free(rs);
   1.115 @@ -1246,7 +1251,7 @@
   1.116                              T("TPK %s is revoked.", primary_fpr_str);
   1.117                              good = false;
   1.118                              cookie->good_but_revoked ++;
   1.119 -                        } else if (! pgp_tpk_alive(tpk)) {
   1.120 +                        } else if (! pgp_tpk_alive(tpk, 0)) {
   1.121                              T("TPK %s is not alive.", primary_fpr_str);
   1.122                              good = false;
   1.123                              cookie->good_but_expired ++;
   1.124 @@ -1271,7 +1276,7 @@
   1.125                                            primary_fpr_str, keyid_str);
   1.126                                          good = false;
   1.127                                          cookie->good_but_revoked ++;
   1.128 -                                    } else if (! pgp_signature_key_alive(sig, key)) {
   1.129 +                                    } else if (! pgp_signature_key_alive(sig, key, 0)) {
   1.130                                          T("TPK %s's signing key %s is expired.",
   1.131                                            primary_fpr_str, keyid_str);
   1.132                                          good = false;
   1.133 @@ -1669,6 +1674,8 @@
   1.134      ws = pgp_signer_new_detached(&err, ws, &signer, 1, 0);
   1.135      if (!ws)
   1.136          ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
   1.137 +    // pgp_signer_new_detached consumes signer.
   1.138 +    signer = NULL;
   1.139  
   1.140      pgp_status_t write_status =
   1.141          pgp_writer_stack_write_all (&err, ws,
   1.142 @@ -1690,7 +1697,11 @@
   1.143  
   1.144   out:
   1.145      pgp_signer_free (signer);
   1.146 -    pgp_key_pair_free (signing_keypair);
   1.147 +    // XXX: pgp_key_pair_as_signer is only supposed to reference
   1.148 +    // signing_keypair, but it consumes it.  If this is fixed, this
   1.149 +    // will become a leak.
   1.150 +    //
   1.151 +    //pgp_key_pair_free (signing_keypair);
   1.152      pgp_tpk_key_iter_free (iter);
   1.153      pgp_tpk_free(signer_tpk);
   1.154  
   1.155 @@ -1704,8 +1715,16 @@
   1.156  {
   1.157      PEP_STATUS status = PEP_STATUS_OK;
   1.158      pgp_error_t err = NULL;
   1.159 -    int keys_count = 0;
   1.160 -    pgp_tpk_t *keys = NULL;
   1.161 +
   1.162 +    int recipient_tpk_count = 0;
   1.163 +    pgp_tpk_t *recipient_tpks = NULL;
   1.164 +
   1.165 +    int recipient_count = 0;
   1.166 +    int recipient_alloc = 0;
   1.167 +    pgp_recipient_t *recipients = NULL;
   1.168 +    int recipient_keys_count = 0;
   1.169 +    pgp_key_t *recipient_keys = NULL;
   1.170 +
   1.171      pgp_tpk_t signer_tpk = NULL;
   1.172      pgp_writer_stack_t ws = NULL;
   1.173      pgp_tpk_key_iter_t iter = NULL;
   1.174 @@ -1722,18 +1741,82 @@
   1.175      *ctext = NULL;
   1.176      *csize = 0;
   1.177  
   1.178 -    keys = calloc(stringlist_length(keylist), sizeof(*keys));
   1.179 -    if (keys == NULL)
   1.180 +    int keylist_len = stringlist_length(keylist);
   1.181 +
   1.182 +    // We don't need to worry about extending recipient_tpks, because
   1.183 +    // there will be at most KEYLIST_LEN tpks, which we allocate up
   1.184 +    // front.
   1.185 +    recipient_tpks = calloc(keylist_len, sizeof(*recipient_tpks));
   1.186 +    if (recipient_tpks == NULL)
   1.187          ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.188  
   1.189 +    // Because there may be multiple encryption keys per TPK, we may
   1.190 +    // need to extend recipient_keys and recipients.
   1.191 +    recipient_alloc = keylist_len;
   1.192 +    recipient_keys = calloc(recipient_alloc, sizeof(*recipient_keys));
   1.193 +    if (recipient_keys == NULL)
   1.194 +        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.195 +
   1.196 +    recipients = calloc(recipient_alloc, sizeof(*recipients));
   1.197 +    if (recipients == NULL)
   1.198 +        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.199 +
   1.200 +
   1.201      // Get the keys for the recipients.
   1.202      const stringlist_t *_keylist;
   1.203      for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
   1.204          assert(_keylist->value);
   1.205 -        pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(_keylist->value);
   1.206 -        status = tpk_find_by_fpr(session, pgp_fpr, false, &keys[keys_count ++], NULL);
   1.207 -        pgp_fingerprint_free(pgp_fpr);
   1.208 -        ERROR_OUT(NULL, status, "Looking up key for recipient '%s'", _keylist->value);
   1.209 +
   1.210 +        pgp_tpk_t tpk;
   1.211 +        status = tpk_find_by_fpr_hex(session, _keylist->value,
   1.212 +                                     false, &tpk, NULL);
   1.213 +        // We couldn't find a key for this recipient.
   1.214 +        ERROR_OUT(NULL, status,
   1.215 +                  "Looking up key for recipient '%s'", _keylist->value);
   1.216 +
   1.217 +        recipient_tpks[recipient_tpk_count ++] = tpk;
   1.218 +
   1.219 +        // Collect all of the keys that have the encryption for
   1.220 +        // transport capability.
   1.221 +        pgp_tpk_key_iter_t iter = pgp_tpk_key_iter_valid(tpk);
   1.222 +        if (! iter)
   1.223 +            ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.224 +        pgp_tpk_key_iter_encrypting_capable_for_transport(iter);
   1.225 +
   1.226 +        pgp_key_t key;
   1.227 +        while ((key = pgp_tpk_key_iter_next (iter, NULL, NULL))) {
   1.228 +            assert(recipient_count == recipient_keys_count);
   1.229 +            if (recipient_count == recipient_alloc) {
   1.230 +                assert(recipient_alloc > 0);
   1.231 +                recipient_alloc *= 2;
   1.232 +
   1.233 +                void *t = reallocarray(recipient_keys, recipient_alloc,
   1.234 +                                       sizeof(*recipient_keys));
   1.235 +                if (! t)
   1.236 +                    ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.237 +                recipient_keys = t;
   1.238 +
   1.239 +                t = reallocarray(recipients, recipient_alloc,
   1.240 +                                 sizeof(*recipients));
   1.241 +                if (! t)
   1.242 +                    ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.243 +                recipients = t;
   1.244 +            }
   1.245 +
   1.246 +            // pgp_recipient_new consumes the passed key id, but it
   1.247 +            // only references key (i.e., we still have to free key).
   1.248 +            pgp_keyid_t keyid = pgp_key_keyid(key);
   1.249 +            if (! key)
   1.250 +                ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.251 +
   1.252 +            key = pgp_key_clone(key);
   1.253 +            if (! key)
   1.254 +                ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.255 +            recipient_keys[recipient_keys_count++] = key;
   1.256 +
   1.257 +            recipients[recipient_count++] = pgp_recipient_new(keyid, key);
   1.258 +        }
   1.259 +        pgp_tpk_key_iter_free(iter);
   1.260      }
   1.261  
   1.262      if (sign) {
   1.263 @@ -1750,11 +1833,14 @@
   1.264  
   1.265      ws = pgp_writer_stack_message(writer);
   1.266      ws = pgp_encryptor_new (&err, ws,
   1.267 -                            NULL, 0, keys, keys_count,
   1.268 -                            PGP_ENCRYPTION_MODE_FOR_TRANSPORT, 0);
   1.269 +                            NULL, 0, recipients, recipient_count,
   1.270 +                            0, 0);
   1.271      if (!ws)
   1.272          ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up encryptor");
   1.273  
   1.274 +    // pgp_encrypt_new consumes the recipients (but not the keys).
   1.275 +    recipient_count = 0;
   1.276 +
   1.277      if (sign) {
   1.278          iter = pgp_tpk_key_iter_valid(signer_tpk);
   1.279          pgp_tpk_key_iter_signing_capable (iter);
   1.280 @@ -1778,6 +1864,8 @@
   1.281          ws = pgp_signer_new(&err, ws, &signer, 1, 0);
   1.282          if (!ws)
   1.283              ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
   1.284 +        // pgp_signer_new consumes signer.
   1.285 +        signer = NULL;
   1.286      }
   1.287  
   1.288      ws = pgp_literal_writer_new (&err, ws);
   1.289 @@ -1809,13 +1897,23 @@
   1.290  
   1.291   out:
   1.292      pgp_signer_free (signer);
   1.293 -    pgp_key_pair_free (signing_keypair);
   1.294 +    // XXX: pgp_key_pair_as_signer is only supposed to reference
   1.295 +    // signing_keypair, but it consumes it.  If this is fixed, this
   1.296 +    // will become a leak.
   1.297 +    //
   1.298 +    // pgp_key_pair_free (signing_keypair);
   1.299      pgp_tpk_key_iter_free (iter);
   1.300      pgp_tpk_free(signer_tpk);
   1.301  
   1.302 -    for (int i = 0; i < keys_count; i ++)
   1.303 -        pgp_tpk_free(keys[i]);
   1.304 -    free(keys);
   1.305 +    for (int i = 0; i < recipient_count; i ++)
   1.306 +        pgp_recipient_free(recipients[i]);
   1.307 +    free(recipients);
   1.308 +    for (int i = 0; i < recipient_keys_count; i ++)
   1.309 +        pgp_key_free(recipient_keys[i]);
   1.310 +    free(recipient_keys);
   1.311 +    for (int i = 0; i < recipient_tpk_count; i ++)
   1.312 +        pgp_tpk_free(recipient_tpks[i]);
   1.313 +    free(recipient_tpks);
   1.314  
   1.315      T("-> %s", pEp_status_to_string(status));
   1.316      return status;
   1.317 @@ -2267,7 +2365,7 @@
   1.318      bool revoked = false;
   1.319      // Don't add revoked keys to the keyinfo_list.
   1.320      if (keyinfo_list) {
   1.321 -        pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
   1.322 +        pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
   1.323          pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
   1.324          pgp_revocation_status_free(rs);
   1.325          if (rsv == PGP_REVOCATION_STATUS_REVOKED)
   1.326 @@ -2469,7 +2567,7 @@
   1.327      status = tpk_find_by_fpr_hex(session, fpr, true, &tpk, NULL);
   1.328      ERROR_OUT(NULL, status, "Looking up '%s'", fpr);
   1.329  
   1.330 -    uint32_t creation_time = pgp_key_creation_time(pgp_tpk_primary(tpk));
   1.331 +    uint32_t creation_time = pgp_key_creation_time(pgp_tpk_primary_key(tpk));
   1.332      if (creation_time > t)
   1.333          // The creation time is after the expiration time!
   1.334          ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
   1.335 @@ -2507,6 +2605,10 @@
   1.336  
   1.337   out:
   1.338      pgp_signer_free (signer);
   1.339 +    // XXX: pgp_key_pair_as_signer is only supposed to reference
   1.340 +    // signing_keypair, but it consumes it.  If this is fixed, this
   1.341 +    // will become a leak.
   1.342 +    //
   1.343      pgp_key_pair_free (keypair);
   1.344      pgp_tpk_key_iter_free (iter);
   1.345      pgp_tpk_free(tpk);
   1.346 @@ -2555,7 +2657,7 @@
   1.347      if (! tpk)
   1.348          ERROR_OUT(err, PEP_UNKNOWN_ERROR, "setting expiration");
   1.349  
   1.350 -    assert(pgp_revocation_status_variant(pgp_tpk_revocation_status(tpk))
   1.351 +    assert(pgp_revocation_status_variant(pgp_tpk_revoked(tpk, 0))
   1.352             == PGP_REVOCATION_STATUS_REVOKED);
   1.353  
   1.354      status = tpk_save(session, tpk, NULL);
   1.355 @@ -2575,7 +2677,7 @@
   1.356  static void _pgp_key_expired(pgp_tpk_t tpk, const time_t when, bool* expired)
   1.357  {
   1.358      // Is the TPK live?
   1.359 -    *expired = !pgp_tpk_alive_at(tpk, when);
   1.360 +    *expired = !pgp_tpk_alive(tpk, when);
   1.361  
   1.362  #ifdef TRACING
   1.363      {
   1.364 @@ -2633,7 +2735,7 @@
   1.365        
   1.366  out:
   1.367      // Er, this might be problematic in terms of internal vs. external in log. FIXME?
   1.368 -    T("(%s) -> %s (expired: %d)", fpr, pEp_status_to_string(status), *expired);
   1.369 +    T(" -> expired: %d", *expired);
   1.370      return;
   1.371  }
   1.372                              
   1.373 @@ -2680,7 +2782,7 @@
   1.374      pgp_fingerprint_free(pgp_fpr);
   1.375      ERROR_OUT(NULL, status, "Looking up %s", fpr);
   1.376  
   1.377 -    pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
   1.378 +    pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
   1.379      *revoked = pgp_revocation_status_variant(rs) == PGP_REVOCATION_STATUS_REVOKED;
   1.380      pgp_revocation_status_free (rs);
   1.381      pgp_tpk_free(tpk);
   1.382 @@ -2724,7 +2826,7 @@
   1.383      //     goto out;
   1.384      // }
   1.385  
   1.386 -    pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
   1.387 +    pgp_revocation_status_t rs = pgp_tpk_revoked(tpk, 0);
   1.388      pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
   1.389      pgp_revocation_status_free(rs);
   1.390      if (rsv == PGP_REVOCATION_STATUS_REVOKED) {
   1.391 @@ -2798,7 +2900,7 @@
   1.392      pgp_fingerprint_free(pgp_fpr);
   1.393      ERROR_OUT(NULL, status, "Looking up %s", fpr);
   1.394  
   1.395 -    pgp_key_t k = pgp_tpk_primary(tpk);
   1.396 +    pgp_key_t k = pgp_tpk_primary_key(tpk);
   1.397      *created = pgp_key_creation_time(k);
   1.398      pgp_tpk_free(tpk);
   1.399  
     2.1 --- a/test/README.md	Wed Nov 20 16:11:25 2019 +0100
     2.2 +++ b/test/README.md	Mon Nov 25 11:00:36 2019 +0100
     2.3 @@ -41,27 +41,29 @@
     2.4  
     2.5  ##### Debian and Ubuntu (and derivatives)
     2.6  
     2.7 -Thanks to Erik Smistad for this starting point (condensed from [Getting Started
     2.8 -with Google Test On
     2.9 -Ubuntu](https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/)):
    2.10 +Using the libgtest-dev is easy, but not straightforward.
    2.11 +Unfortunately, the version of google test in Debian Buster is too old:
    2.12 +it's version 1.8 and we require version 1.9.  Version 1.9 is available
    2.13 +in Debian Testing, but it is built with g++ 9.0, which is ABI
    2.14 +incompatible with binaries built with g++ 8.0, which is in Debian
    2.15 +stable.  Specifically, gcc has changed the semantics of std::string
    2.16 +with C++11 and using g++ 8.0 results in the errors like the following:
    2.17  
    2.18 -  1. Install the packages `cmake` and `libgtest-dev` from the repository. This
    2.19 -  will install the gtest source files to `/usr/src/gtest`. You'll still need to
    2.20 -  compile the code and link the library files to be able to use them.
    2.21 +    undefined reference to `std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream()'
    2.22  
    2.23 -  2. Compile the source files:
    2.24 -  ```
    2.25 -  cd /usr/src/gtest
    2.26 -  sudo cmake CMakeLists.txt
    2.27 -  sudo make
    2.28 -  ```
    2.29 +It's possible to install g++ 9.0 from testing to get the test suite
    2.30 +working, but that breaks other things (at least for me -Neal).
    2.31 +Instead, the easiest thing to do it to rebuild gtest for Debian
    2.32 +Stable.  This is straightforward:
    2.33  
    2.34 -  3. Copy/symlink the libraries to the library location of your choice (here,
    2.35 -  it's `/usr/lib`, hence the `sudo`, but as long as it's in your library path,
    2.36 -  it shouldn't matter where you stick it):
    2.37 -  ```
    2.38 -  sudo cp *.a /usr/lib
    2.39 -  ```
    2.40 +  $ sudo apt install build-essential cmake debhelper
    2.41 +  $ apt source -t testing libgtest-dev
    2.42 +  $ cd googletest-1.9.0.20190831
    2.43 +  $ dpkg-buildpackage -us -uc
    2.44 +  ...
    2.45 +  $ sudo dpkg -i googletest_1.9.0.20190831-1_amd64.deb libgtest-dev_1.9.0.20190831-1_amd64.deb
    2.46 +
    2.47 +That's it.
    2.48  
    2.49  ##### MacOS
    2.50  
    2.51 @@ -197,6 +199,9 @@
    2.52    gdb --args ./EngineTests --gtest_filter=TestSuiteName.test_function_name
    2.53    ```
    2.54  
    2.55 +When debugging a failing test, use '--gtest_break_on_failure' to have
    2.56 +gtest automatically break into the debugger where the assertion fails.
    2.57 +
    2.58  # Creating new tests
    2.59  
    2.60  Script next on the agenda...
     3.1 --- a/test/src/test_util.cc	Wed Nov 20 16:11:25 2019 +0100
     3.2 +++ b/test/src/test_util.cc	Mon Nov 25 11:00:36 2019 +0100
     3.3 @@ -13,6 +13,7 @@
     3.4  #include <sstream>
     3.5  #include <iostream>
     3.6  #include <stdexcept>
     3.7 +#include <algorithm>
     3.8  #include <stdlib.h>
     3.9  #include <sys/stat.h>
    3.10  #include <errno.h>