diff options
Diffstat (limited to 'src/camel/tests/message')
-rw-r--r-- | src/camel/tests/message/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/camel/tests/message/README | 8 | ||||
-rw-r--r-- | src/camel/tests/message/test1.c | 212 | ||||
-rw-r--r-- | src/camel/tests/message/test2.c | 385 | ||||
-rw-r--r-- | src/camel/tests/message/test4.c | 122 |
5 files changed, 734 insertions, 0 deletions
diff --git a/src/camel/tests/message/CMakeLists.txt b/src/camel/tests/message/CMakeLists.txt new file mode 100644 index 000000000..e9f9bea77 --- /dev/null +++ b/src/camel/tests/message/CMakeLists.txt @@ -0,0 +1,7 @@ +set(TESTS + test1 + test2 + test4 +) + +add_camel_tests(message TESTS) diff --git a/src/camel/tests/message/README b/src/camel/tests/message/README new file mode 100644 index 000000000..f5624e7c9 --- /dev/null +++ b/src/camel/tests/message/README @@ -0,0 +1,8 @@ + +test1 creating, saving, loading simple messages +test2 camelinternetaddress tests, internationalised addresses, etc. +test4 more encompassing mime parser tests that test real-world messages. + Note: In order to test this, though, you'll need to fetch + http://primates.ximian.com/~fejj/camel-mime-tests.tar.gz and + untar it into camel/tests/data/ + diff --git a/src/camel/tests/message/test1.c b/src/camel/tests/message/test1.c new file mode 100644 index 000000000..472456ef7 --- /dev/null +++ b/src/camel/tests/message/test1.c @@ -0,0 +1,212 @@ +/* + * 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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* + test1.c + * + Create a message, save it. + * + Retrieve message, compare content. + * + Operations: + writing / loading from different types of streams + reading / writing different content + reading / writing different encodings + reading / writing different charsets + * + Just testing streams: + different stream types + different file ops + seek, eof, etc. +*/ + +#include "camel-test.h" +#include "messages.h" + +/* for stat */ +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +struct _text { + gchar *text; + gint len; +}; + +#define MAX_TEXTS (14) +struct _text texts[MAX_TEXTS]; + +static void +setup (void) +{ + gint i, j; + gchar *p; + + /* setup various edge and other general cases */ + texts[0].text = g_strdup (""); + texts[0].len = 0; + texts[1].text = g_strdup (""); + texts[1].len = 1; + texts[2].text = g_strdup ("\n"); + texts[2].len = 1; + texts[3].text = g_strdup ("A"); + texts[3].len = 1; + texts[4].text = g_strdup ("This is a test.\n."); + texts[4].len = strlen (texts[4].text); + texts[5].text = g_strdup ("This is a test.\n\n.\n"); + texts[5].len = strlen (texts[5].text); + texts[6].text = g_malloc0 (1024); + texts[6].len = 1024; + texts[7].text = g_malloc0 (102400); + texts[7].len = 102400; + texts[8].text = g_malloc (1024); + memset (texts[8].text, '\n', 1024); + texts[8].len = 1024; + texts[9].text = g_malloc (102400); + memset (texts[9].text, '\n', 102400); + texts[9].len = 102400; + texts[10].text = g_malloc (1024); + memset (texts[10].text, ' ', 1024); + texts[10].len = 1024; + texts[11].text = g_malloc (102400); + memset (texts[11].text, ' ', 102400); + texts[11].len = 102400; + + srand (42); + p = texts[12].text = g_malloc (1024); + for (i = 0; i < 1024; i++) { + j = rand (); + if (j < RAND_MAX / 120) + *p++ = '\n'; + else + *p++ = (j % 95) + 32; + } + texts[12].len = 1024; + p = texts[13].text = g_malloc (102400); + for (i = 0; i < 102400; i++) { + j = rand (); + if (j < RAND_MAX / 120) + *p++ = '\n'; + else + *p++ = (j % 95) + 32; + } + texts[13].len = 102400; +} + +static void +cleanup (void) +{ + gint i; + + for (i = 0; i < MAX_TEXTS; i++) + g_free (texts[i].text); +} + +gint +main (gint argc, + gchar **argv) +{ + CamelMimeMessage *msg, *msg2; + gint i, j; + gchar *text; + gint len; + + camel_test_init (argc, argv); + + setup (); + + camel_test_start ("Simple memory-based content creation"); + + /* test all ways of setting simple content for a message (i.e. memory based) */ + for (j = 0; j < MAX_TEXTS; j++) { + push ("testing text number %d", j); + text = texts[j].text; + len = texts[j].len; + for (i = 0; i < SET_CONTENT_WAYS; i++) { + push ("create simple message %d", i); + msg = test_message_create_simple (); + + push ("set simple content"); + test_message_set_content_simple ((CamelMimePart *) msg, i, "text/plain", text, len); + pull (); + + push ("compare original content"); + test_message_compare_content (camel_medium_get_content ((CamelMedium *) msg), text, len); + pull (); + + push ("save message to test1.msg"); + unlink ("test1.msg"); + test_message_write_file (msg, "test1.msg"); + check_unref (msg, 1); + pull (); + + push ("read from test1.msg"); + msg2 = test_message_read_file ("test1.msg"); + pull (); + + push ("compare read with original content"); + test_message_compare_content (camel_medium_get_content ((CamelMedium *) msg2), text, len); + check_unref (msg2, 1); + pull (); + + unlink ("test1.msg"); + pull (); + } + pull (); + } + + camel_test_end (); + + camel_test_start ("Different encodings"); + for (j = 0; j < MAX_TEXTS; j++) { + push ("testing text number %d", j); + text = texts[j].text; + len = texts[j].len; + for (i = 0; i < CAMEL_TRANSFER_NUM_ENCODINGS; i++) { + + push ("test simple message, encoding %s", camel_transfer_encoding_to_string (i)); + msg = test_message_create_simple (); + + push ("set simple content"); + test_message_set_content_simple ((CamelMimePart *) msg, 0, "text/plain", text, len); + pull (); + + camel_mime_part_set_encoding ((CamelMimePart *) msg, i); + + push ("save message to test1.msg"); + unlink ("test1.msg"); + test_message_write_file (msg, "test1.msg"); + check_unref (msg, 1); + pull (); + + push ("read from test1.msg"); + msg2 = test_message_read_file ("test1.msg"); + pull (); + + push ("compare read with original content"); + test_message_compare_content (camel_medium_get_content ((CamelMedium *) msg2), text, len); + check_unref (msg2, 1); + pull (); + + unlink ("test1.msg"); + pull (); + } + pull (); + } + camel_test_end (); + + cleanup (); + + return 0; +} diff --git a/src/camel/tests/message/test2.c b/src/camel/tests/message/test2.c new file mode 100644 index 000000000..ada3c1dc6 --- /dev/null +++ b/src/camel/tests/message/test2.c @@ -0,0 +1,385 @@ +/* + * 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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "camel-test.h" +#include "messages.h" +#include "addresses.h" + +/* for stat */ +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <iconv.h> + +#include "address-data.h" + +static gchar *convert (const gchar *in, const gchar *from, const gchar *to) +{ + GIConv ic = g_iconv_open (to, from); + gchar *out, *outp; + const gchar *inp; + gsize inlen, outlen; + + if (ic == (GIConv) -1) + return g_strdup (in); + + inlen = strlen (in); + outlen = inlen * 5 + 16; + + outp = out = g_malloc (outlen); + inp = in; + + if (iconv (ic, &inp, &inlen, &outp, &outlen) == -1) { + test_free (out); + g_iconv_close (ic); + return g_strdup (in); + } + + if (iconv (ic, NULL, 0, &outp, &outlen) == -1) { + test_free (out); + g_iconv_close (ic); + return g_strdup (in); + } + + g_iconv_close (ic); + + *outp = 0; + +#if 0 + /* lets see if we can convert back again? */ + { + gchar *nout, *noutp; + GIConv ic = iconv_open (from, to); + + if (ic == (GIConv) -1) + goto fail; + + inp = out; + inlen = strlen (out); + outlen = inlen * 5 + 16; + noutp = nout = g_malloc (outlen); + if (iconv (ic, &inp, &inlen, &noutp, &outlen) == -1 + || iconv (ic, NULL, 0, &noutp, &outlen) == -1) { + g_warning ("Cannot convert '%s' \n from %s to %s: %s\n", in, to, from, g_strerror (errno)); + } + iconv_close (ic); + } + + /* and lets see what camel thinks out optimal charset is */ + { + printf ( + "Camel thinks the best encoding of '%s' is %s, although we converted from %s\n", + in, camel_charset_best (out, strlen (out)), from); + } +fail: +#endif + + return out; +} + +static void +check_address_line_decode (gint i, + const gchar *line, + const gchar *name, + const gchar *email) +{ + CamelInternetAddress *addr; + const gchar *dname, *demail; + + push ("Testing address line %d '%s'", i, line); + dname = NULL; + demail = NULL; + addr = camel_internet_address_new (); + check (camel_address_decode (CAMEL_ADDRESS (addr), line) == 1); + check (camel_internet_address_get (CAMEL_INTERNET_ADDRESS (addr), 0, &dname, &demail)); + check_msg (g_strcmp0 (dname, name) == 0 || (!name && dname && !*dname), "decoded name = '%s', but should be '%s'", dname, name); + check_msg (g_strcmp0 (demail, email) == 0, "decoded email = '%s', but should be '%s'", demail, email); + check_unref (addr, 1); + pull (); +} + +#define to_utf8(in, type) convert(in, type, "utf-8") +#define from_utf8(in, type) convert(in, "utf-8", type) + +gint main (gint argc, gchar **argv) +{ + gint i; + CamelInternetAddress *addr, *addr2; + gchar *name; + const gchar *charset; + const gchar *real, *where; + gchar *enc, *enc2, *format, *format2; + + camel_test_init (argc, argv); + + camel_test_start ("CamelInternetAddress, basics"); + + addr = camel_internet_address_new (); + + push ("Test blank address"); + check (camel_address_length (CAMEL_ADDRESS (addr)) == 0); + check (camel_internet_address_get (addr, 0, &real, &where) == FALSE); + pull (); + + push ("Test blank clone"); + addr2 = CAMEL_INTERNET_ADDRESS (camel_address_new_clone (CAMEL_ADDRESS (addr))); + test_address_compare (addr, addr2); + check_unref (addr2, 1); + pull (); + + push ("Test add 1"); + camel_internet_address_add (addr, "Zed", "nowhere@here.com.au"); + check (camel_address_length (CAMEL_ADDRESS (addr)) == 1); + check (camel_internet_address_get (addr, 0, &real, &where) == TRUE); + check_msg (string_equal ("Zed", real), "real = '%s'", real); + check (strcmp (where, "nowhere@here.com.au") == 0); + pull (); + + push ("Test clone 1"); + addr2 = CAMEL_INTERNET_ADDRESS (camel_address_new_clone (CAMEL_ADDRESS (addr))); + test_address_compare (addr, addr2); + check_unref (addr2, 1); + pull (); + + push ("Test add many"); + for (i = 1; i < 10; i++) { + gchar name[16], a[32]; + g_snprintf (name, sizeof (name), "Zed %d", i); + g_snprintf (a, sizeof (a), "nowhere@here-%d.com.au", i); + camel_internet_address_add (addr, name, a); + check (camel_address_length (CAMEL_ADDRESS (addr)) == i + 1); + check (camel_internet_address_get (addr, i, &real, &where) == TRUE); + check_msg (string_equal (name, real), "name = '%s' real = '%s'", name, real); + check (strcmp (where, a) == 0); + } + pull (); + + /* put a few of these in to make it look like its doing something impressive ... :) */ + camel_test_end (); + camel_test_start ("CamelInternetAddress, search"); + + push ("Test search"); + camel_test_nonfatal ("Address comparisons should ignore whitespace??"); + check (camel_internet_address_find_name (addr, "Zed 1", &where) == 1); + check (camel_internet_address_find_name (addr, "Zed 9", &where) == 9); + check (camel_internet_address_find_name (addr, "Zed", &where) == 0); + check (camel_internet_address_find_name (addr, " Zed", &where) == 0); + check (camel_internet_address_find_name (addr, "Zed ", &where) == 0); + check (camel_internet_address_find_name (addr, " Zed ", &where) == 0); + check (camel_internet_address_find_name (addr, "Zed 20", &where) == -1); + check (camel_internet_address_find_name (addr, "", &where) == -1); + /* interface dont handle nulls :) */ + /*check(camel_internet_address_find_name(addr, NULL, &where) == -1);*/ + + check (camel_internet_address_find_address (addr, "nowhere@here-1.com.au", &where) == 1); + check (camel_internet_address_find_address (addr, "nowhere@here-1 . com.au", &where) == 1); + check (camel_internet_address_find_address (addr, "nowhere@here-2 .com.au ", &where) == 2); + check (camel_internet_address_find_address (addr, " nowhere @here-3.com.au", &where) == 3); + check (camel_internet_address_find_address (addr, "nowhere@here-20.com.au ", &where) == -1); + check (camel_internet_address_find_address (addr, "", &where) == -1); + /*check(camel_internet_address_find_address(addr, NULL, &where) == -1);*/ + camel_test_fatal (); + pull (); + + camel_test_end (); + camel_test_start ("CamelInternetAddress, copy/cat/clone"); + + push ("Test clone many"); + addr2 = CAMEL_INTERNET_ADDRESS (camel_address_new_clone (CAMEL_ADDRESS (addr))); + test_address_compare (addr, addr2); + pull (); + + push ("Test remove items"); + camel_address_remove (CAMEL_ADDRESS (addr2), 0); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 9); + camel_address_remove (CAMEL_ADDRESS (addr2), 0); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 8); + camel_address_remove (CAMEL_ADDRESS (addr2), 5); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 7); + camel_address_remove (CAMEL_ADDRESS (addr2), 10); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 7); + camel_address_remove (CAMEL_ADDRESS (addr2), -1); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 0); + check_unref (addr2, 1); + pull (); + + push ("Testing copy/cat"); + push ("clone + cat"); + addr2 = CAMEL_INTERNET_ADDRESS (camel_address_new_clone (CAMEL_ADDRESS (addr))); + camel_address_cat (CAMEL_ADDRESS (addr2), CAMEL_ADDRESS (addr)); + check (camel_address_length (CAMEL_ADDRESS (addr)) == 10); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 20); + check_unref (addr2, 1); + pull (); + + push ("cat + cat + copy"); + addr2 = camel_internet_address_new (); + camel_address_cat (CAMEL_ADDRESS (addr2), CAMEL_ADDRESS (addr)); + test_address_compare (addr, addr2); + camel_address_cat (CAMEL_ADDRESS (addr2), CAMEL_ADDRESS (addr)); + check (camel_address_length (CAMEL_ADDRESS (addr)) == 10); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 20); + camel_address_copy (CAMEL_ADDRESS (addr2), CAMEL_ADDRESS (addr)); + test_address_compare (addr, addr2); + check_unref (addr2, 1); + pull (); + + push ("copy"); + addr2 = camel_internet_address_new (); + camel_address_copy (CAMEL_ADDRESS (addr2), CAMEL_ADDRESS (addr)); + test_address_compare (addr, addr2); + check_unref (addr2, 1); + pull (); + + pull (); + + check_unref (addr, 1); + + camel_test_end (); + + camel_test_start ("CamelInternetAddress, I18N"); + + for (i = 0; i < G_N_ELEMENTS (test_lines); i++) { + push ("Testing text line %d (%s) '%s'", i, test_lines[i].type, test_lines[i].line); + + addr = camel_internet_address_new (); + + /* first, convert to api format (utf-8) */ + charset = test_lines[i].type; + name = to_utf8 (test_lines[i].line, charset); + + push ("Address setup"); + camel_internet_address_add (addr, name, "nobody@nowhere.com"); + check (camel_internet_address_get (addr, 0, &real, &where) == TRUE); + check_msg (string_equal (name, real), "name = '%s' real = '%s'", name, real); + check (strcmp (where, "nobody@nowhere.com") == 0); + test_free (name); + + check (camel_internet_address_get (addr, 1, &real, &where) == FALSE); + check (camel_address_length (CAMEL_ADDRESS (addr)) == 1); + pull (); + + push ("Address encode/decode"); + enc = camel_address_encode (CAMEL_ADDRESS (addr)); + + addr2 = camel_internet_address_new (); + check (camel_address_decode (CAMEL_ADDRESS (addr2), enc) == 1); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 1); + + enc2 = camel_address_encode (CAMEL_ADDRESS (addr2)); + check_msg (string_equal (enc, enc2), "enc = '%s' enc2 = '%s'", enc, enc2); + test_free (enc2); + + push ("Compare addresses"); + test_address_compare (addr, addr2); + pull (); + check_unref (addr2, 1); + test_free (enc); + pull (); + + /* FIXME: format/unformat arne't guaranteed to be reversible, at least at the moment */ + camel_test_nonfatal ("format/unformat not (yet) reversible for all cases"); + + push ("Address format/unformat"); + format = camel_address_format (CAMEL_ADDRESS (addr)); + + addr2 = camel_internet_address_new (); + check (camel_address_unformat (CAMEL_ADDRESS (addr2), format) == 1); + check (camel_address_length (CAMEL_ADDRESS (addr2)) == 1); + + format2 = camel_address_format (CAMEL_ADDRESS (addr2)); + check_msg (string_equal (format, format2), "format = '%s\n\tformat2 = '%s'", format, format2); + test_free (format2); + + /* currently format/unformat doesn't handle ,'s and other special chars at all */ + if (camel_address_length (CAMEL_ADDRESS (addr2)) == 1) { + push ("Compare addresses"); + test_address_compare (addr, addr2); + pull (); + } + + test_free (format); + pull (); + + camel_test_fatal (); + + check_unref (addr2, 1); + + check_unref (addr, 1); + pull (); + + } + + camel_test_end (); + + camel_test_start ("CamelInternetAddress, I18N decode"); + + for (i = 0; i < G_N_ELEMENTS (test_address); i++) { + push ("Testing address line %d '%s'", i, test_address[i].addr); + + addr = camel_internet_address_new (); + push ("checking decoded"); + check (camel_address_decode (CAMEL_ADDRESS (addr), test_address[i].addr) == test_address[i].count); + format = camel_address_format (CAMEL_ADDRESS (addr)); + check (strcmp (format, test_address[i].utf8) == 0); + test_free (format); + pull (); + + push ("Comparing re-encoded output"); + addr2 = CAMEL_INTERNET_ADDRESS (camel_internet_address_new ()); + enc = camel_address_encode (CAMEL_ADDRESS (addr)); + check_msg (camel_address_decode (CAMEL_ADDRESS (addr2), enc) == test_address[i].count, "enc = '%s'", enc); + test_free (enc); + test_address_compare (addr, addr2); + check_unref (addr2, 1); + pull (); + + check_unref (addr, 1); + + pull (); + } + + camel_test_end (); + + camel_test_start ("CamelInternerAddress name & email decoder"); + + for (i = 0; i < G_N_ELEMENTS (test_decode); i++) { + gchar *line; + const gchar *name, *email; + gint jj; + + name = test_decode[i].name; + email = test_decode[i].email; + + for (jj = 0; jj < G_N_ELEMENTS (line_decode_formats); jj++) { + if (line_decode_formats[jj].without_name) { + line = g_strdup_printf (line_decode_formats[jj].without_name, email); + check_address_line_decode (i, line, NULL, email); + g_free (line); + } + + if (!name) + continue; + + line = g_strdup_printf (line_decode_formats[jj].with_name, name, email); + check_address_line_decode (i, line, name, email); + g_free (line); + } + } + + camel_test_end (); + + return 0; +} diff --git a/src/camel/tests/message/test4.c b/src/camel/tests/message/test4.c new file mode 100644 index 000000000..16442521f --- /dev/null +++ b/src/camel/tests/message/test4.c @@ -0,0 +1,122 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + * 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. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Jeffrey Stedfast <fejj@ximian.com> + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> + +#include "camel-test.h" +#include "messages.h" + +#if 0 +static void +dump_mime_struct (CamelMimePart *mime_part, + gint depth) +{ + CamelDataWrapper *content; + gchar *mime_type; + gint i = 0; + + while (i < depth) { + printf (" "); + i++; + } + + content = camel_medium_get_content ((CamelMedium *) mime_part); + + mime_type = camel_data_wrapper_get_mime_type (content); + printf ("Content-Type: %s\n", mime_type); + g_free (mime_type); + + if (CAMEL_IS_MULTIPART (content)) { + guint num, index = 0; + + num = camel_multipart_get_number ((CamelMultipart *) content); + while (index < num) { + mime_part = camel_multipart_get_part ((CamelMultipart *) content, index); + dump_mime_struct (mime_part, depth + 1); + index++; + } + } else if (CAMEL_IS_MIME_MESSAGE (content)) { + dump_mime_struct ((CamelMimePart *) content, depth + 1); + } +} +#endif + +gint main (gint argc, gchar **argv) +{ + struct dirent *dent; + DIR *dir; + gint fd; + + camel_test_init (argc, argv); + + camel_test_start ("Message Test Suite"); + + if (!(dir = opendir ("../data/messages"))) + return 77; + + while ((dent = readdir (dir)) != NULL) { + CamelMimeMessage *message; + CamelStream *stream; + gchar *filename; + struct stat st; + + if (dent->d_name[0] == '.') + continue; + + filename = g_strdup_printf ("../data/messages/%s", dent->d_name); + if (g_stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { + g_free (filename); + continue; + } + + if ((fd = open (filename, O_RDONLY)) == -1) { + g_free (filename); + continue; + } + + push ("testing message '%s'", filename); + g_free (filename); + + stream = camel_stream_fs_new_with_fd (fd); + message = camel_mime_message_new (); + camel_data_wrapper_construct_from_stream_sync ( + CAMEL_DATA_WRAPPER (message), stream, NULL, NULL); + g_seekable_seek ( + G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); + + /*dump_mime_struct ((CamelMimePart *) message, 0);*/ + test_message_compare (message); + + g_object_unref (message); + g_object_unref (stream); + + pull (); + } + + closedir (dir); + + camel_test_end (); + + return 0; +} |