aboutsummaryrefslogtreecommitdiff
path: root/tests/fixture.vala
blob: 7adc434f61fc1cbc326f029e6e4bf9f89cb69b21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * Copyright (C) 2014 Canonical Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authored by Michal Hruby <michal.hruby@canonical.com>
 *
 * This file is taken from libunity.
 */

/* A bit of magic to get proper-ish fixture support */
public interface Fixture : Object
{
  class DelegateWrapper
  {
    TestDataFunc func;
    public DelegateWrapper (owned TestDataFunc f) { func = (owned) f; }
  }

  public virtual void setup () {}
  public virtual void teardown () {}

  [CCode (has_target = false)]
  public delegate void Callback<T> (T ptr);

  private static List<DelegateWrapper> _tests;

  public static unowned TestDataFunc create<F> (Callback<void*> cb)
    requires (typeof (F).is_a (typeof (Fixture)))
  {
    TestDataFunc functor = () =>
    {
      var type = typeof (F);
      var instance = Object.new (type) as Fixture;
      instance.setup ();
      cb (instance);
      instance.teardown ();
    };
    unowned TestDataFunc copy = functor;
    _tests.append (new DelegateWrapper ((owned) functor));
    return copy;
  }
  public static unowned TestDataFunc create_static<F> (Callback<F> cb)
  {
    return create<F> ((Callback<void*>) cb);
  }
}

public static bool run_with_timeout (MainLoop ml, uint timeout_ms = 5000)
{
  bool timeout_reached = false;
  var t_id = Timeout.add (timeout_ms, () =>
  {
    timeout_reached = true;
    debug ("Timeout reached");
    ml.quit ();
    return false;
  });

  ml.run ();

  if (!timeout_reached) Source.remove (t_id);

  return !timeout_reached;
}

/* calling this will ensure that the object was destroyed, but note that
 * it needs to be called with the (owned) modifier */
public static void ensure_destruction (owned Object obj)
{
  var ml = new MainLoop ();
  bool destroyed = false;
  obj.weak_ref (() => { destroyed = true; ml.quit (); });

  obj = null;
  if (!destroyed)
  {
    // wait a bit if there were async operations
    assert (run_with_timeout (ml));
  }
}

public class ErrorHandler
{
  public ErrorHandler ()
  {
    GLib.Test.log_set_fatal_handler (handle_fatal_func);
  }

  private bool handle_fatal_func (string? log_domain, LogLevelFlags flags,
                                  string message)
  {
    return false;
  }

  private uint[] handler_ids;
  private GenericArray<string?> handler_domains;

  public void ignore_message (string? domain, LogLevelFlags flags)
  {
    handler_ids += Log.set_handler (domain, flags | LogLevelFlags.FLAG_FATAL,
                                    () => {});
    if (handler_domains == null)
    {
      handler_domains = new GenericArray<string?> ();
    }
    handler_domains.add (domain);
  }

  ~ErrorHandler ()
  {
    for(uint i = 0; i < handler_ids.length; i++)
      Log.remove_handler (handler_domains[i], handler_ids[i]);
  }
}