geary/test/test-case.vala
Michael Gratton 9c115bec38 Clean up protocol date handling substantially
In RFC822.Date, don't use duplicate time_t and GLib.DateTime properties
-- just use the latter, fix formatting of half-hour time zones, fix
where the that class refers to ISO 8601 instead of RFC822 strings since
that is just plain wrong, and finally when parsing an RFC 822 string,
take note of the timezone offset and store that in the DateTime object,
so it is round-tripped correctly.

Stop passing time_t around everywhere else, just use the UNIX time from
the DateTimes we store for protocol objects anyway, so the time zone is
obvious.

Add unit tests.
2019-03-23 15:21:18 +11:00

353 lines
9.8 KiB
Vala

/*
* Copyright (C) 2009 Julien Peeters
* Copyright (C) 2017-2018 Michael Gratton <mike@vee.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author:
* Julien Peeters <contact@julienpeeters.fr>
* Michael Gratton <mike@vee.net>
*/
public void assert_null(Object? actual, string? context = null)
throws Error {
if (actual != null) {
print_assert(context ?? "Object is non-null", null);
assert_not_reached();
}
}
public void assert_non_null(Object? actual, string? context = null)
throws Error {
if (actual == null) {
print_assert(context ?? "Object is null", null);
assert_not_reached();
}
}
public void assert_equal(Object expected, Object? actual, string? context = null)
throws Error {
if (expected != actual) {
print_assert(context ?? "Objects are not equal", null);
assert_not_reached();
}
}
public void assert_string(string expected, string? actual, string? context = null)
throws Error {
if (expected != actual) {
string a = expected;
if (a.length > 32) {
a = a[0:32] + "";
}
string? b = actual;
if (b != null) {
if (b.length > 32) {
b = b[0:32] + "";
}
}
if (b != null) {
print_assert("Expected: \"%s\", was: \"%s\"".printf(a, b), context);
} else {
print_assert("Expected: \"%s\", was null".printf(a), context);
}
assert_not_reached();
}
}
public void assert_null_string(string? actual, string? context = null)
throws Error {
if (actual != null) {
string a = actual;
if (a.length > 70) {
a = a[0:70] + "";
}
print_assert("Expected: null, was: \"%s\"".printf(a), context);
assert_not_reached();
}
}
public void assert_int(int expected, int actual, string? context = null)
throws Error {
if (expected != actual) {
print_assert("Expected: %d, was: %d".printf(expected, actual), context);
assert_not_reached();
}
}
public void assert_int64(int64 expected, int64 actual, string? context = null)
throws Error {
if (expected != actual) {
print_assert("Expected: %lld, was: %lld".printf(expected, actual), context);
assert_not_reached();
}
}
public void assert_uint(uint expected, uint actual, string? context = null)
throws GLib.Error {
if (expected != actual) {
print_assert("Expected: %u, was: %u".printf(expected, actual), context);
assert_not_reached();
}
}
public void assert_true(bool condition, string? context = null)
throws Error {
if (!condition) {
print_assert(context ?? "Expected true", null);
assert_not_reached();
}
}
public void assert_false(bool condition, string? context = null)
throws Error {
if (condition) {
print_assert(context ?? "Expected false", null);
assert_not_reached();
}
}
public void assert_error(Error expected, Error? actual, string? context = null) {
bool failed = false;
if (actual == null) {
print_assert(
"Expected error: %s %i, was null".printf(
expected.domain.to_string(), expected.code
),
context
);
failed = true;
} else if (expected.domain != actual.domain ||
expected.code != actual.code) {
print_assert(
"Expected error: %s %i, was actually %s %i: %s".printf(
expected.domain.to_string(),
expected.code,
actual.domain.to_string(),
actual.code,
actual.message
),
context
);
failed = true;
}
if (failed) {
assert_not_reached();
}
}
// XXX this shadows GLib.assert_no_error since that doesn't work
public void assert_no_error(Error? err, string? context = null) {
if (err != null) {
print_assert(
"Unexpected error: %s %i: %s".printf(
err.domain.to_string(),
err.code,
err.message
),
context
);
assert_not_reached();
}
}
private inline void print_assert(string message, string? context) {
string output = message;
if (context != null) {
output = "%s: %s".printf(context, output);
}
GLib.stderr.puts(output);
GLib.stderr.putc('\n');
}
public void delete_file(File parent) throws GLib.Error {
FileInfo info = parent.query_info(
"standard::*",
FileQueryInfoFlags.NOFOLLOW_SYMLINKS
);
if (info.get_file_type () == FileType.DIRECTORY) {
FileEnumerator enumerator = parent.enumerate_children(
"standard::*",
FileQueryInfoFlags.NOFOLLOW_SYMLINKS
);
info = null;
while (((info = enumerator.next_file()) != null)) {
delete_file(parent.get_child(info.get_name()));
}
}
parent.delete();
}
public abstract class TestCase : Object {
/** GLib.File URI for resources in test/data. */
public const string RESOURCE_URI = "resource:///org/gnome/GearyTest";
private class SignalWaiter : Object {
public bool was_fired = false;
public void @callback(Object source) {
was_fired = true;
}
}
protected MainContext main_loop = MainContext.default();
private GLib.TestSuite suite;
private Adaptor[] adaptors = new Adaptor[0];
private AsyncQueue<AsyncResult> async_results = new AsyncQueue<AsyncResult>();
public delegate void TestMethod() throws Error;
protected TestCase(string name) {
this.suite = new GLib.TestSuite(name);
}
public void add_test(string name, owned TestMethod test) {
var adaptor = new Adaptor(name, (owned) test, this);
this.adaptors += adaptor;
this.suite.add(
new GLib.TestCase(
adaptor.name,
adaptor.set_up,
adaptor.run,
adaptor.tear_down
)
);
}
public virtual void set_up() throws Error {
}
public virtual void tear_down() throws Error {
}
public GLib.TestSuite get_suite() {
return this.suite;
}
protected void async_complete(AsyncResult result) {
this.async_results.push(result);
// notify the loop so that if async_result() has already been
// called, that method won't block
this.main_loop.wakeup();
}
protected AsyncResult async_result() {
AsyncResult? result = null;
while (result == null) {
this.main_loop.iteration(true);
result = this.async_results.try_pop();
}
return result;
}
/**
* Waits for a mock object's call to be completed.
*
* This method busy waits on the test's main loop until either
* until {@link ExpectedCall.was_called} is true, or until the
* given timeout in seconds has occurred.
*
* Returns //true// if the call was made, or //false// if the
* timeout was reached.
*/
protected bool wait_for_call(ExpectedCall call, double timeout = 1.0) {
GLib.Timer timer = new GLib.Timer();
timer.start();
while (!call.was_called && timer.elapsed() < timeout) {
this.main_loop.iteration(false);
}
return call.was_called;
}
/**
* Waits for an object's signal to be fired.
*
* This method busy waits on the test's main loop until either
* until the object emits the named signal, or until the given
* timeout in seconds has occurred.
*
* Returns //true// if the signal was fired, or //false// if the
* timeout was reached.
*/
protected bool wait_for_signal(Object source, string name, double timeout = 0.5) {
SignalWaiter handler = new SignalWaiter();
ulong id = GLib.Signal.connect_swapped(
source, name, (GLib.Callback) handler.callback, handler
);
GLib.Timer timer = new GLib.Timer();
timer.start();
while (!handler.was_fired && timer.elapsed() < timeout) {
this.main_loop.iteration(false);
}
source.disconnect(id);
return handler.was_fired;
}
private class Adaptor {
public string name { get; private set; }
private TestMethod test;
private TestCase test_case;
public Adaptor(string name,
owned TestMethod test,
TestCase test_case) {
this.name = name;
this.test = (owned) test;
this.test_case = test_case;
}
public void set_up(void* fixture) {
try {
this.test_case.set_up();
} catch (Error err) {
assert_no_error(err);
}
}
public void run(void* fixture) {
try {
this.test();
} catch (Error err) {
assert_no_error(err);
}
}
public void tear_down(void* fixture) {
try {
this.test_case.tear_down();
} catch (Error err) {
assert_no_error(err);
}
}
}
}