Browse Source

Port to GtkSource* API

There are still bugs but this gets it started
tags/1.4.0
JosephMcc 4 years ago
parent
commit
f05ddd7b63
49 changed files with 1797 additions and 8132 deletions
  1. +1
    -5
      Makefile.am
  2. +0
    -9
      configure.ac
  3. +6
    -0
      data/org.x.editor.gschema.xml.in
  4. +3
    -3
      docs/reference/Makefile.am
  5. +0
    -1
      docs/reference/xed-docs.sgml
  6. +1
    -23
      docs/reference/xed-sections.txt
  7. +15
    -23
      docs/reference/xed.types
  8. +21
    -19
      plugins/filebrowser/xed-file-browser-plugin.c
  9. +0
    -1
      plugins/modelines/xed-modeline-plugin.c
  10. +47
    -46
      plugins/spell/xed-spell-plugin.c
  11. +0
    -3
      plugins/trailsave/xed-trail-save-plugin.c
  12. +0
    -1
      po/POTFILES.in
  13. +0
    -24
      tests/Makefile.am
  14. +0
    -155
      tests/document-input-stream.c
  15. +0
    -244
      tests/document-loader.c
  16. +0
    -371
      tests/document-output-stream.c
  17. +0
    -722
      tests/document-saver.c
  18. +0
    -27
      tests/setup-document-saver.sh
  19. +0
    -10
      xed/Makefile.am
  20. +44
    -30
      xed/dialogs/xed-encodings-dialog.c
  21. +63
    -69
      xed/xed-commands-file.c
  22. +4
    -4
      xed/xed-commands.h
  23. +0
    -479
      xed/xed-document-input-stream.c
  24. +0
    -68
      xed/xed-document-input-stream.h
  25. +0
    -930
      xed/xed-document-loader.c
  26. +0
    -102
      xed/xed-document-loader.h
  27. +0
    -911
      xed/xed-document-output-stream.c
  28. +0
    -70
      xed/xed-document-output-stream.h
  29. +0
    -1024
      xed/xed-document-saver.c
  30. +0
    -103
      xed/xed-document-saver.h
  31. +333
    -929
      xed/xed-document.c
  32. +14
    -101
      xed/xed-document.h
  33. +17
    -17
      xed/xed-encodings-combo-box.c
  34. +16
    -18
      xed/xed-encodings-combo-box.h
  35. +0
    -545
      xed/xed-encodings.c
  36. +0
    -65
      xed/xed-encodings.h
  37. +45
    -40
      xed/xed-file-chooser-dialog.c
  38. +12
    -13
      xed/xed-file-chooser-dialog.h
  39. +38
    -60
      xed/xed-io-error-message-area.c
  40. +4
    -4
      xed/xed-io-error-message-area.h
  41. +1
    -0
      xed/xed-settings.h
  42. +924
    -753
      xed/xed-tab.c
  43. +14
    -15
      xed/xed-tab.h
  44. +67
    -0
      xed/xed-utils.c
  45. +6
    -2
      xed/xed-utils.h
  46. +19
    -7
      xed/xed-view-frame.c
  47. +24
    -26
      xed/xed-window.c
  48. +3
    -4
      xed/xed-window.h
  49. +55
    -56
      xed/xed.c

+ 1
- 5
Makefile.am View File

@@ -3,10 +3,6 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}

SUBDIRS = xed pixmaps po data plugins docs help

if ENABLE_TESTS
SUBDIRS += tests
endif

distuninstallcheck_listfiles = find . -type f -print

EXTRA_DIST = \
@@ -55,7 +51,7 @@ MAINTAINERCLEANFILES = \
m4/lt~obsolete.m4 \
`find "$(srcdir)" -type f -name Makefile.in -print`

DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --disable-tests
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc

dist-hook:
@if test -d "$(srcdir)/.git"; \


+ 0
- 9
configure.ac View File

@@ -213,13 +213,6 @@ if test "x$enable_deprecations" = "xyes"; then
AC_SUBST(DISABLE_DEPRECATED_CFLAGS)
fi

AC_ARG_ENABLE([tests],
AS_HELP_STRING([--enable-tests], [Enable the tests]),
[enable_tests=$enableval],
[enable_tests=yes])

AM_CONDITIONAL(ENABLE_TESTS, test x$enable_tests = xyes)

PLUGIN_LIBTOOL_FLAGS="-module -avoid-version"

AC_SUBST(PLUGIN_LIBTOOL_FLAGS)
@@ -259,7 +252,6 @@ plugins/time/Makefile
plugins/time/org.x.editor.plugins.time.gschema.xml
plugins/trailsave/Makefile
po/Makefile.in
tests/Makefile
])

AC_OUTPUT
@@ -273,5 +265,4 @@ Configuration:
Spell Plugin enabled: $enable_enchant
Gvfs metadata enabled: $enable_gvfs_metadata
GObject Introspection: ${have_introspection}
Tests enabled: $enable_tests
"

+ 6
- 0
data/org.x.editor.gschema.xml.in View File

@@ -155,6 +155,12 @@
<description>Whether xed should enable syntax highlighting.</description>
</key>

<key name="ensure-trailing-newline" type="b">
<default>true</default>
<summary>Ensure Trailing Newline</summary>
<description>Whether gedit will ensure that documents always end with a trailing newline.</description>
</key>

</schema>

<schema gettext-domain="@GETTEXT_PACKAGE@" id="org.x.editor.preferences.ui" path="/org/x/editor/preferences/ui/">


+ 3
- 3
docs/reference/Makefile.am View File

@@ -21,7 +21,7 @@ SCANGOBJ_OPTIONS=

# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
SCAN_OPTIONS=
SCAN_OPTIONS = --rebuild-types

# Extra options to supply to gtkdoc-mkdb.
MKDB_OPTIONS=--sgml-mode --output-format=xml
@@ -41,8 +41,6 @@ CFILE_GLOB=$(top_srcdir)/xed/*.c
# Header files to ignore when scanning (These are internal to xed).
IGNORE_HFILES= \
xed-commands.h \
xed-document-loader.h \
xed-document-saver.h \
xed-documents-panel.h \
xed-io-error-message-area.h \
xed-languages-manager.h \
@@ -92,6 +90,8 @@ GTKDOC_LIBS= \
$(top_builddir)/xed/libxed.la \
$(XED_LIBS)

MAINTAINERCLEANFILES = xed.types

# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make



+ 0
- 1
docs/reference/xed-docs.sgml View File

@@ -28,7 +28,6 @@
<xi:include href="xml/xed-window.xml"/>
<xi:include href="xml/xed-convert.xml"/>
<xi:include href="xml/xed-debug.xml"/>
<xi:include href="xml/xed-encodings.xml"/>
<xi:include href="xml/xed-help.xml"/>
<xi:include href="xml/xed-metadata-manager.xml"/>
<xi:include href="xml/xed-utils.xml"/>


+ 1
- 23
docs/reference/xed-sections.txt View File

@@ -39,20 +39,14 @@ xed_app_activatable_get_type
XedDocumentPrivate
<TITLE>XedDocument</TITLE>
XedDocument
XedDocumentSaveFlags
XED_DOCUMENT_ERROR
xed_document_error_quark
xed_document_new
xed_document_get_file
xed_document_get_location
xed_document_get_uri_for_display
xed_document_get_short_name_for_display
xed_document_get_mime_type
xed_document_get_readonly
xed_document_load
xed_document_insert_file
xed_document_load_cancel
xed_document_save
xed_document_save_as
xed_document_is_untouched
xed_document_is_untitled
xed_document_get_deleted
@@ -458,22 +452,6 @@ xed_debug
xed_debug_message
</SECTION>

<SECTION>
<FILE>xed-encodings</FILE>
XedEncoding
XED_TYPE_ENCODING
xed_encoding_get_type
xed_encoding_copy
xed_encoding_free
xed_encoding_get_from_charset
xed_encoding_get_from_index
xed_encoding_to_string
xed_encoding_get_name
xed_encoding_get_charset
xed_encoding_get_utf8
xed_encoding_get_current
</SECTION>

<SECTION>
<FILE>xed-help</FILE>
xed_help_display


+ 15
- 23
docs/reference/xed.types View File

@@ -1,36 +1,28 @@
#include "xed-app.h"
#include "xed-app-activatable.h"
#include "xed-document.h"
#include "xed-encodings.h"
#include "xed-encodings-combo-box.h"
#include "xed-file-chooser-dialog.h"
#include "xed-message.h"
#include "xed-message-bus.h"
#include "xed-message-type.h"
#include "xed-notebook.h"
#include "xed-panel.h"
#include "xed-progress-message-area.h"
#include "xed-statusbar.h"
#include "xed-tab.h"
#include "xed-view.h"
#include "xed-view-activatable.h"
#include "xed-window.h"
#include "xed-window-activatable.h"
xed_app_get_type
egg_sm_client_get_type
egg_sm_client_xsmp_get_type
xed_app_activatable_get_type
xed_app_get_type
xed_close_button_get_type
xed_document_get_type
xed_encoding_get_type
xed_encodings_combo_box_get_type
xed_file_chooser_dialog_get_type
xed_message_get_type
xed_history_entry_get_type
xed_message_bus_get_type
xed_message_get_type
xed_message_type_get_type
xed_notebook_get_type
xed_panel_get_type
xed_print_job_get_type
xed_print_preview_get_type
xed_progress_message_area_get_type
xed_searchbar_get_type
xed_settings_get_type
xed_status_combo_box_get_type
xed_statusbar_get_type
xed_tab_get_type
xed_view_get_type
xed_tab_label_get_type
xed_view_activatable_get_type
xed_window_get_type
xed_view_frame_get_type
xed_view_get_type
xed_window_activatable_get_type
xed_window_get_type

+ 21
- 19
plugins/filebrowser/xed-file-browser-plugin.c View File

@@ -302,7 +302,8 @@ set_root_from_doc (XedFileBrowserPlugin *plugin,
XedDocument *doc)
{
XedFileBrowserPluginPrivate *priv = plugin->priv;
GFile *file;
GtkSourceFile *file;
GFile *location;
GFile *parent;

if (doc == NULL)
@@ -310,13 +311,14 @@ set_root_from_doc (XedFileBrowserPlugin *plugin,
return;
}

file = xed_document_get_location (doc);
if (file == NULL)
file = xed_document_get_file (doc);
location = gtk_source_file_get_location (file);
if (location == NULL)
{
return;
}

parent = g_file_get_parent (file);
parent = g_file_get_parent (location);

if (parent != NULL)
{
@@ -326,8 +328,6 @@ set_root_from_doc (XedFileBrowserPlugin *plugin,

g_object_unref (parent);
}

g_object_unref (file);
}

static void
@@ -764,8 +764,6 @@ on_rename_cb (XedFileBrowserStore *store,
XedApp *app;
GList *documents;
GList *item;
XedDocument *doc;
GFile *docfile;

/* Find all documents and set its uri to newuri where it matches olduri */
app = xed_app_get_default ();
@@ -773,17 +771,22 @@ on_rename_cb (XedFileBrowserStore *store,

for (item = documents; item; item = item->next)
{
XedDocument *doc;
GtkSourceFile *source_file;
GFile *docfile;

doc = XED_DOCUMENT (item->data);
docfile = xed_document_get_location (doc);
source_file = xed_document_get_file (doc);
docfile = gtk_source_file_get_location (source_file);

if (!docfile)
if (docfile == NULL)
{
continue;
}

if (g_file_equal (docfile, oldfile))
{
xed_document_set_location (doc, newfile);
gtk_source_file_set_location (source_file, newfile);
}
else
{
@@ -791,22 +794,20 @@ on_rename_cb (XedFileBrowserStore *store,

relative = g_file_get_relative_path (oldfile, docfile);

if (relative)
if (relative != NULL)
{
/* relative now contains the part in docfile without
the prefix oldfile */

g_object_unref (docfile);

docfile = g_file_get_child (newfile, relative);

xed_document_set_location (doc, docfile);
gtk_source_file_set_location (source_file, docfile);

g_object_unref (docfile);
}

g_free (relative);
}

g_object_unref (docfile);
}

g_list_free (documents);
@@ -895,10 +896,12 @@ on_tab_added_cb (XedWindow *window,
if (open)
{
XedDocument *doc;
GtkSourceFile *file;
GFile *location;

doc = xed_tab_get_document (tab);
location = xed_document_get_location (doc);
file = xed_document_get_file (doc);
location = gtk_source_file_get_location (file);

if (location != NULL)
{
@@ -908,7 +911,6 @@ on_tab_added_cb (XedWindow *window,
set_root_from_doc (plugin, doc);
load_default = FALSE;
}
g_object_unref (location);
}
}



+ 0
- 1
plugins/modelines/xed-modeline-plugin.c View File

@@ -141,7 +141,6 @@ xed_modeline_plugin_get_property (GObject *object,

static void
on_document_loaded_or_saved (XedDocument *document,
const GError *error,
GtkSourceView *view)
{
modeline_parser_apply_modeline (view);


+ 47
- 46
plugins/spell/xed-spell-plugin.c View File

@@ -45,6 +45,8 @@
#define XED_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::xed-spell-language"
#define XED_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::xed-spell-enabled"

#define XED_AUTOMATIC_SPELL_VIEW "XedAutomaticSpellView"

#define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_1"

#define XED_SPELL_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
@@ -1009,12 +1011,15 @@ spell_cb (GtkAction *action,
}

static void
set_auto_spell (XedWindow *window,
XedDocument *doc,
gboolean active)
set_auto_spell (XedWindow *window,
XedView *view,
gboolean active)
{
XedAutomaticSpellChecker *autospell;
XedSpellChecker *spell;
XedDocument *doc;

doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));

spell = get_spell_checker_from_document (doc);
g_return_if_fail (spell != NULL);
@@ -1025,13 +1030,8 @@ set_auto_spell (XedWindow *window,
{
if (autospell == NULL)
{
XedView *active_view;

active_view = xed_window_get_active_view (window);
g_return_if_fail (active_view != NULL);

autospell = xed_automatic_spell_checker_new (doc, spell);
xed_automatic_spell_checker_attach_view (autospell, active_view);
xed_automatic_spell_checker_attach_view (autospell, view);
xed_automatic_spell_checker_recheck_all (autospell);
}
}
@@ -1050,6 +1050,7 @@ auto_spell_cb (GtkAction *action,
{
XedSpellPluginPrivate *priv;
XedDocument *doc;
XedView *view;
gboolean active;

xed_debug (DEBUG_PLUGINS);
@@ -1059,12 +1060,14 @@ auto_spell_cb (GtkAction *action,

xed_debug_message (DEBUG_PLUGINS, active ? "Auto Spell activated" : "Auto Spell deactivated");

doc = xed_window_get_active_document (priv->window);
if (doc == NULL)
view = xed_window_get_active_view (priv->window);
if (view == NULL)
{
return;
}

doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));

if (get_autocheck_type (plugin) == AUTOCHECK_DOCUMENT)
{
xed_document_set_metadata (doc,
@@ -1072,33 +1075,32 @@ auto_spell_cb (GtkAction *action,
active ? "1" : NULL, NULL);
}

set_auto_spell (priv->window, doc, active);
set_auto_spell (priv->window, view, active);
}

static void
update_ui (XedSpellPlugin *plugin)
{
XedSpellPluginPrivate *priv;
XedDocument *doc;
XedView *view;
gboolean autospell;
GtkAction *action;

xed_debug (DEBUG_PLUGINS);

priv = plugin->priv;
doc = xed_window_get_active_document (priv->window);
view = xed_window_get_active_view (priv->window);

autospell = (doc != NULL && xed_automatic_spell_checker_get_from_document (doc) != NULL);

if (doc != NULL)
if (view != NULL)
{
XedDocument *doc;
XedTab *tab;
XedTabState state;
gboolean autospell;

doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
tab = xed_window_get_active_tab (priv->window);
state = xed_tab_get_state (tab);
autospell = (doc != NULL && xed_automatic_spell_checker_get_from_document (doc) != NULL);

/* If the document is loading we can't get the metadata so we
endup with an useless speller */
@@ -1107,7 +1109,7 @@ update_ui (XedSpellPlugin *plugin)
action = gtk_action_group_get_action (priv->action_group, "AutoSpell");

g_signal_handlers_block_by_func (action, auto_spell_cb, plugin);
set_auto_spell (priv->window, doc, autospell);
set_auto_spell (priv->window, view, autospell);
gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), autospell);
g_signal_handlers_unblock_by_func (action, auto_spell_cb, plugin);
}
@@ -1120,15 +1122,18 @@ update_ui (XedSpellPlugin *plugin)

static void
set_auto_spell_from_metadata (XedSpellPlugin *plugin,
XedDocument *doc,
XedView *view,
GtkActionGroup *action_group)
{
gboolean active = FALSE;
gchar *active_str = NULL;
XedWindow *window;
XedDocument *doc;
XedDocument *active_doc;
XedSpellPluginAutocheckType autocheck_type;

doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));

autocheck_type = get_autocheck_type (plugin);

switch (autocheck_type)
@@ -1158,7 +1163,7 @@ set_auto_spell_from_metadata (XedSpellPlugin *plugin,

window = XED_WINDOW (plugin->priv->window);

set_auto_spell (window, doc, active);
set_auto_spell (window, view, active);

/* In case that the doc is the active one we mark the spell action */
active_doc = xed_window_get_active_document (window);
@@ -1177,37 +1182,31 @@ set_auto_spell_from_metadata (XedSpellPlugin *plugin,

static void
on_document_loaded (XedDocument *doc,
const GError *error,
XedSpellPlugin *plugin)
{
if (error == NULL)
{
XedSpellChecker *spell;

spell = XED_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id));
if (spell != NULL)
{
set_language_from_metadata (spell, doc);
}
XedSpellChecker *spell;
XedView *view;

set_auto_spell_from_metadata (plugin, doc, plugin->priv->action_group);
spell = XED_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id));
if (spell != NULL)
{
set_language_from_metadata (spell, doc);
}

view = XED_VIEW (g_object_get_data (G_OBJECT (doc), XED_AUTOMATIC_SPELL_VIEW));

set_auto_spell_from_metadata (plugin, view, plugin->priv->action_group);
}

static void
on_document_saved (XedDocument *doc,
const GError *error,
XedSpellPlugin *plugin)
{
XedAutomaticSpellChecker *autospell;
XedSpellChecker *spell;
const gchar *key;

if (error != NULL)
{
return;
}

/* Make sure to save the metadata here too */
autospell = xed_automatic_spell_checker_get_from_document (doc);
spell = XED_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id));
@@ -1242,9 +1241,13 @@ tab_added_cb (XedWindow *window,
XedTab *tab,
XedSpellPlugin *plugin)
{
XedView *view;
XedDocument *doc;

doc = xed_tab_get_document (tab);
view = xed_tab_get_view (tab);
doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));

g_object_set_data (G_OBJECT (doc), XED_AUTOMATIC_SPELL_VIEW, view);

g_signal_connect (doc, "loaded",
G_CALLBACK (on_document_loaded), plugin);
@@ -1261,6 +1264,7 @@ tab_removed_cb (XedWindow *window,
XedDocument *doc;

doc = xed_tab_get_document (tab);
g_object_set_data (G_OBJECT (doc), XED_AUTOMATIC_SPELL_VIEW, NULL);

g_signal_handlers_disconnect_by_func (doc, on_document_loaded, plugin);
g_signal_handlers_disconnect_by_func (doc, on_document_saved, plugin);
@@ -1271,7 +1275,7 @@ xed_spell_plugin_activate (XedWindowActivatable *activatable)
{
XedSpellPluginPrivate *priv;
GtkUIManager *manager;
GList *docs, *l;
GList *views, *l;

xed_debug (DEBUG_PLUGINS);

@@ -1323,15 +1327,12 @@ xed_spell_plugin_activate (XedWindowActivatable *activatable)

update_ui (XED_SPELL_PLUGIN (activatable));

docs = xed_window_get_documents (priv->window);
for (l = docs; l != NULL; l = g_list_next (l))
views = xed_window_get_views (priv->window);
for (l = views; l != NULL; l = g_list_next (l))
{
XedDocument *doc = XED_DOCUMENT (l->data);

set_auto_spell_from_metadata (XED_SPELL_PLUGIN (activatable), doc, priv->action_group);
XedView *view = XED_VIEW (l->data);

g_signal_handlers_disconnect_by_func (doc, on_document_loaded, activatable);
g_signal_handlers_disconnect_by_func (doc, on_document_saved, activatable);
set_auto_spell_from_metadata (XED_SPELL_PLUGIN (activatable), view, priv->action_group);
}

priv->tab_added_id = g_signal_connect (priv->window, "tab-added",


+ 0
- 3
plugins/trailsave/xed-trail-save-plugin.c View File

@@ -128,9 +128,6 @@ strip_trailing_spaces (GtkTextBuffer *text_buffer)

static void
on_save (XedDocument *document,
const gchar *uri,
XedEncoding *encoding,
XedDocumentSaveFlags save_flags,
XedTrailSavePlugin *plugin)
{
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (document);


+ 0
- 1
po/POTFILES.in View File

@@ -16,7 +16,6 @@ xed/xed-commands-help.c
xed/xed-commands-search.c
xed/xed-debug.c
xed/xed-document.c
xed/xed-document-saver.c
xed/xed-documents-panel.c
xed/xed-encodings.c
xed/xed-encodings-combo-box.c


+ 0
- 24
tests/Makefile.am View File

@@ -1,24 +0,0 @@
AM_CPPFLAGS = -g -I$(top_srcdir) -I$(top_srcdir)/xed $(XED_DEBUG_FLAGS) $(XED_CFLAGS)

noinst_PROGRAMS = $(TEST_PROGS)
progs_ldadd = $(top_builddir)/xed/libxed.la

TEST_PROGS = document-input-stream
document_input_stream_SOURCES = document-input-stream.c
document_input_stream_LDADD = $(progs_ldadd)

TEST_PROGS += document-output-stream
document_output_stream_SOURCES = document-output-stream.c
document_output_stream_LDADD = $(progs_ldadd)

TEST_PROGS += document-loader
document_loader_SOURCES = document-loader.c
document_loader_LDADD = $(progs_ldadd)

TEST_PROGS += document-saver
document_saver_SOURCES = document-saver.c
document_saver_LDADD = $(progs_ldadd)

TESTS = $(TEST_PROGS)

EXTRA_DIST = setup-document-saver.sh

+ 0
- 155
tests/document-input-stream.c View File

@@ -1,155 +0,0 @@
/*
* document-input-stream.c
* This file is part of xed
*
* Copyright (C) 2010 - Ignacio Casal Quinteiro
*
* xed is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* xed 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 xed; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/


#include "xed-document-input-stream.h"
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <string.h>

static void
test_consecutive_read (const gchar *inbuf,
const gchar *outbuf,
XedDocumentNewlineType type,
gsize read_chunk_len)
{
GtkTextBuffer *buf;
GInputStream *in;
gsize outlen;
gssize n, r;
GError *err = NULL;
gchar *b;
gboolean close;

buf = gtk_text_buffer_new (NULL);
gtk_text_buffer_set_text (buf, inbuf, -1);

b = g_malloc (200);
in = xed_document_input_stream_new (buf, type);

outlen = strlen (outbuf);
n = 0;

do
{
r = g_input_stream_read (in, b + n, read_chunk_len, NULL, &err);
g_assert_cmpint (r, >=, 0);
g_assert_no_error (err);

n += r;
} while (r != 0);

g_assert_cmpint (n, ==, outlen);

b[n] = '\0';

g_assert_cmpstr (b, ==, outbuf);

close = g_input_stream_close (in, NULL, &err);
g_assert (close);
g_assert_no_error (err);

g_object_unref (buf);
g_object_unref (in);
g_free (b);
}

static void
test_empty ()
{
/* empty file should not have a trailing newline */
test_consecutive_read ("", "", XED_DOCUMENT_NEWLINE_TYPE_CR_LF, 10);
}

static void
test_consecutive_cut_char ()
{
/* first \n is read then fo and then is added \r but not \n */
test_consecutive_read ("\nfo\nbar\n\nblah\n", "\r\nfo\r\nbar\r\n\r\nblah\r\n\r\n", XED_DOCUMENT_NEWLINE_TYPE_CR_LF, 8);
test_consecutive_read ("\nfo\nbar\n\nblah", "\r\nfo\r\nbar\r\n\r\nblah\r\n", XED_DOCUMENT_NEWLINE_TYPE_CR_LF, 8);
}

static void
test_consecutive_big_read ()
{
test_consecutive_read ("\nfo\nbar\n\nblah\n", "\rfo\rbar\r\rblah\r\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 200);
test_consecutive_read ("\nfo\nbar\n\nblah", "\rfo\rbar\r\rblah\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 200);

test_consecutive_read ("\rfo\rbar\r\rblah\r", "\nfo\nbar\n\nblah\n\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 200);
test_consecutive_read ("\rfo\rbar\r\rblah", "\nfo\nbar\n\nblah\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 200);

test_consecutive_read ("\r\nfo\r\nbar\r\n\r\nblah\r\n", "\nfo\nbar\n\nblah\n\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 200);
test_consecutive_read ("\r\nfo\r\nbar\r\n\r\nblah", "\nfo\nbar\n\nblah\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 200);

test_consecutive_read ("\nfo\nbar\n\nblah\n", "\r\nfo\r\nbar\r\n\r\nblah\r\n\r\n", XED_DOCUMENT_NEWLINE_TYPE_CR_LF, 200);
test_consecutive_read ("\nfo\nbar\n\nblah", "\r\nfo\r\nbar\r\n\r\nblah\r\n", XED_DOCUMENT_NEWLINE_TYPE_CR_LF, 200);
}

static void
test_consecutive_middle_read ()
{
test_consecutive_read ("\nfo\nbar\n\nblah\n", "\rfo\rbar\r\rblah\r\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 6);
test_consecutive_read ("\nfo\nbar\n\nblah", "\rfo\rbar\r\rblah\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 6);

test_consecutive_read ("\rfo\rbar\r\rblah\r", "\nfo\nbar\n\nblah\n\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 6);
test_consecutive_read ("\rfo\rbar\r\rblah", "\nfo\nbar\n\nblah\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 6);

test_consecutive_read ("\r\nfo\r\nbar\r\n\r\nblah\r\n", "\nfo\nbar\n\nblah\n\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 6);
test_consecutive_read ("\r\nfo\r\nbar\r\n\r\nblah", "\nfo\nbar\n\nblah\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 6);

test_consecutive_read ("\nfo\nbar\n\nblah\n", "\r\nfo\r\nbar\r\n\r\nblah\r\n\r\n", XED_DOCUMENT_NEWLINE_TYPE_CR_LF, 6);
test_consecutive_read ("\nfo\nbar\n\nblah", "\r\nfo\r\nbar\r\n\r\nblah\r\n", XED_DOCUMENT_NEWLINE_TYPE_CR_LF, 6);
}

static void
test_consecutive_multibyte_cut ()
{
test_consecutive_read ("hello\nhello\xe6\x96\x87\nworld\n", "hello\rhello\xe6\x96\x87\rworld\r\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 6);
test_consecutive_read ("hello\rhello\xe6\x96\x87\rworld\r", "hello\rhello\xe6\x96\x87\rworld\r\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 6);
test_consecutive_read ("hello\nhello\xe6\x96\x87\nworld\n", "hello\nhello\xe6\x96\x87\nworld\n\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 6);
}

static void
test_consecutive_multibyte_big_read ()
{
test_consecutive_read ("hello\nhello\xe6\x96\x87\nworld\n", "hello\rhello\xe6\x96\x87\rworld\r\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 200);
test_consecutive_read ("hello\rhello\xe6\x96\x87\rworld\r", "hello\rhello\xe6\x96\x87\rworld\r\r", XED_DOCUMENT_NEWLINE_TYPE_CR, 200);
test_consecutive_read ("hello\nhello\xe6\x96\x87\nworld\n", "hello\nhello\xe6\x96\x87\nworld\n\n", XED_DOCUMENT_NEWLINE_TYPE_LF, 200);
}

int main (int argc,
char *argv[])
{
g_test_init (&argc, &argv, NULL);

g_test_add_func ("/document-input-stream/empty", test_empty);

g_test_add_func ("/document-input-stream/consecutive_cut_char", test_consecutive_cut_char);
g_test_add_func ("/document-input-stream/consecutive_big_read", test_consecutive_big_read);
g_test_add_func ("/document-input-stream/consecutive_middle_read", test_consecutive_middle_read);

g_test_add_func ("/document-input-stream/consecutive_multibyte_cut", test_consecutive_multibyte_cut);
g_test_add_func ("/document-input-stream/consecutive_multibyte_big_read", test_consecutive_multibyte_big_read);

return g_test_run ();
}

+ 0
- 244
tests/document-loader.c View File

@@ -1,244 +0,0 @@
/*
* document-loader.c
* This file is part of xed
*
* Copyright (C) 2010 - Jesse van den Kieboom
*
* xed is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* xed 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 xed; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/

#include "xed-document-loader.h"
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <string.h>

static gboolean test_completed;

typedef struct
{
const gchar *in_buffer;
gint newline_type;
GFile *file;
} LoaderTestData;

static GFile *
create_document (const gchar *filename,
const gchar *contents)
{
GError *error = NULL;
XedDocument *document;
gchar *uri;

if (!g_file_set_contents (filename, contents, -1, &error))
{
g_assert_no_error (error);
}

return g_file_new_for_path (filename);
}

static void
delete_document (GFile *location)
{
if (g_file_query_exists (location, NULL))
{
GError *err = NULL;

g_file_delete (location, NULL, &err);
g_assert_no_error (err);
}

test_completed = TRUE;
}

static void
on_document_loaded (XedDocument *document,
GError *error,
LoaderTestData *data)
{
GtkTextIter start, end;

g_assert_no_error (error);

if (data->in_buffer != NULL)
{
gchar *text;

gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (document), &start, &end);
text = gtk_text_iter_get_slice (&start, &end);

g_assert_cmpstr (text, ==, data->in_buffer);

g_free (text);
}

if (data->newline_type != -1)
{
g_assert_cmpint (xed_document_get_newline_type (document),
==,
data->newline_type);
}

delete_document (data->file);
}

static void
test_loader (const gchar *filename,
const gchar *contents,
const gchar *in_buffer,
gint newline_type)
{
GFile *file;
gchar *uri;
XedDocument *document;

file = create_document (filename, contents);

document = xed_document_new ();

LoaderTestData *data = g_slice_new (LoaderTestData);
data->in_buffer = in_buffer;
data->newline_type = newline_type;
data->file = file;

test_completed = FALSE;

g_signal_connect (document,
"loaded",
G_CALLBACK (on_document_loaded),
data);

xed_document_load (document, file, xed_encoding_get_utf8 (), 0, FALSE);

while (!test_completed)
{
g_main_context_iteration (NULL, TRUE);
}

g_slice_free (LoaderTestData, data);
g_object_unref (file);
g_object_unref (document);
}

static void
test_end_line_stripping ()
{
test_loader ("document-loader.txt",
"hello world\n",
"hello world",
-1);

test_loader ("document-loader.txt",
"hello world",
"hello world",
-1);

test_loader ("document-loader.txt",
"\nhello world",
"\nhello world",
-1);

test_loader ("document-loader.txt",
"\nhello world\n",
"\nhello world",
-1);

test_loader ("document-loader.txt",
"hello world\n\n",
"hello world\n",
-1);

test_loader ("document-loader.txt",
"hello world\r\n",
"hello world",
-1);

test_loader ("document-loader.txt",
"hello world\r\n\r\n",
"hello world\r\n",
-1);

test_loader ("document-loader.txt",
"\n",
"",
-1);

test_loader ("document-loader.txt",
"\r\n",
"",
-1);

test_loader ("document-loader.txt",
"\n\n",
"\n",
-1);

test_loader ("document-loader.txt",
"\r\n\r\n",
"\r\n",
-1);
}

static void
test_end_new_line_detection ()
{
test_loader ("document-loader.txt",
"hello world\n",
NULL,
XED_DOCUMENT_NEWLINE_TYPE_LF);

test_loader ("document-loader.txt",
"hello world\r\n",
NULL,
XED_DOCUMENT_NEWLINE_TYPE_CR_LF);

test_loader ("document-loader.txt",
"hello world\r",
NULL,
XED_DOCUMENT_NEWLINE_TYPE_CR);
}

static void
test_begin_new_line_detection ()
{
test_loader ("document-loader.txt",
"\nhello world",
NULL,
XED_DOCUMENT_NEWLINE_TYPE_LF);

test_loader ("document-loader.txt",
"\r\nhello world",
NULL,
XED_DOCUMENT_NEWLINE_TYPE_CR_LF);

test_loader ("document-loader.txt",
"\rhello world",
NULL,
XED_DOCUMENT_NEWLINE_TYPE_CR);
}

int main (int argc,
char *argv[])
{
g_test_init (&argc, &argv, NULL);

g_test_add_func ("/document-loader/end-line-stripping", test_end_line_stripping);
g_test_add_func ("/document-loader/end-new-line-detection", test_end_new_line_detection);
g_test_add_func ("/document-loader/begin-new-line-detection", test_begin_new_line_detection);

return g_test_run ();
}

+ 0
- 371
tests/document-output-stream.c View File

@@ -1,371 +0,0 @@
/*
* document-output-stream.c
* This file is part of xed
*
* Copyright (C) 2010 - Ignacio Casal Quinteiro
*
* xed is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* xed 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 xed; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/


#include "xed-document-output-stream.h"
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <string.h>

static void
test_consecutive_write (const gchar *inbuf,
const gchar *outbuf,
gsize write_chunk_len,
XedDocumentNewlineType newline_type)
{
XedDocument *doc;
GOutputStream *out;
gsize len;
gssize n, w;
GError *err = NULL;
gchar *b;
XedDocumentNewlineType type;
GSList *encodings = NULL;

doc = xed_document_new ();
encodings = g_slist_prepend (encodings, (gpointer)xed_encoding_get_utf8 ());
out = xed_document_output_stream_new (doc, encodings);

n = 0;

do
{
len = MIN (write_chunk_len, strlen (inbuf + n));
w = g_output_stream_write (out, inbuf + n, len, NULL, &err);
g_assert_cmpint (w, >=, 0);
g_assert_no_error (err);

n += w;
} while (w != 0);

g_assert(g_output_stream_flush (out, NULL, &err) == TRUE);
g_assert_no_error (err);

g_object_get (G_OBJECT (doc), "text", &b, NULL);

g_assert_cmpstr (inbuf, ==, b);
g_free (b);

type = xed_document_output_stream_detect_newline_type (XED_DOCUMENT_OUTPUT_STREAM (out));
g_assert (type == newline_type);

g_output_stream_close (out, NULL, &err);
g_assert_no_error (err);

g_object_get (G_OBJECT (doc), "text", &b, NULL);

g_assert_cmpstr (outbuf, ==, b);
g_free (b);

g_assert (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)) == FALSE);

g_object_unref (doc);
g_object_unref (out);
}

static void
test_empty ()
{
test_consecutive_write ("", "", 10, XED_DOCUMENT_NEWLINE_TYPE_DEFAULT);
test_consecutive_write ("\r\n", "", 10, XED_DOCUMENT_NEWLINE_TYPE_CR_LF);
test_consecutive_write ("\r", "", 10, XED_DOCUMENT_NEWLINE_TYPE_CR);
test_consecutive_write ("\n", "", 10, XED_DOCUMENT_NEWLINE_TYPE_LF);
}

static void
test_consecutive ()
{
test_consecutive_write ("hello\nhow\nare\nyou", "hello\nhow\nare\nyou", 3,
XED_DOCUMENT_NEWLINE_TYPE_LF);
test_consecutive_write ("hello\rhow\rare\ryou", "hello\rhow\rare\ryou", 3,
XED_DOCUMENT_NEWLINE_TYPE_CR);
test_consecutive_write ("hello\r\nhow\r\nare\r\nyou", "hello\r\nhow\r\nare\r\nyou", 3,
XED_DOCUMENT_NEWLINE_TYPE_CR_LF);
}

static void
test_consecutive_tnewline ()
{
test_consecutive_write ("hello\nhow\nare\nyou\n", "hello\nhow\nare\nyou", 3,
XED_DOCUMENT_NEWLINE_TYPE_LF);
test_consecutive_write ("hello\rhow\rare\ryou\r", "hello\rhow\rare\ryou", 3,
XED_DOCUMENT_NEWLINE_TYPE_CR);
test_consecutive_write ("hello\r\nhow\r\nare\r\nyou\r\n", "hello\r\nhow\r\nare\r\nyou", 3,
XED_DOCUMENT_NEWLINE_TYPE_CR_LF);
}

static void
test_big_char ()
{
test_consecutive_write ("\343\203\200\343\203\200", "\343\203\200\343\203\200", 2,
XED_DOCUMENT_NEWLINE_TYPE_LF);
}

/* SMART CONVERSION */

#define TEXT_TO_CONVERT "this is some text to make the tests"
#define TEXT_TO_GUESS "hello \xe6\x96\x87 world"

static void
print_hex (gchar *ptr, gint len)
{
gint i;

for (i = 0; i < len; ++i)
{
g_printf ("\\x%02x", (unsigned char)ptr[i]);
}

g_printf ("\n");
}

static gchar *
get_encoded_text (const gchar *text,
gsize nread,
const XedEncoding *to,
const XedEncoding *from,
gsize *bytes_written_aux,
gboolean care_about_error)
{
GCharsetConverter *converter;
gchar *out, *out_aux;
gsize bytes_read, bytes_read_aux;
gsize bytes_written;
GConverterResult res;
GError *err;

converter = g_charset_converter_new (xed_encoding_get_charset (to),
xed_encoding_get_charset (from),
NULL);

out = g_malloc (200);
out_aux = g_malloc (200);
err = NULL;
bytes_read_aux = 0;
*bytes_written_aux = 0;

if (nread == -1)
{
nread = strlen (text);
}

do
{
res = g_converter_convert (G_CONVERTER (converter),
text + bytes_read_aux,
nread,
out_aux,
200,
G_CONVERTER_INPUT_AT_END,
&bytes_read,
&bytes_written,
&err);
memcpy (out + *bytes_written_aux, out_aux, bytes_written);
bytes_read_aux += bytes_read;
*bytes_written_aux += bytes_written;
nread -= bytes_read;
} while (res != G_CONVERTER_FINISHED && res != G_CONVERTER_ERROR);

if (care_about_error)
{
g_assert_no_error (err);
}
else if (err)
{
g_printf ("** You don't care, but there was an error: %s", err->message);
return NULL;
}

out[*bytes_written_aux] = '\0';

if (!g_utf8_validate (out, *bytes_written_aux, NULL) && !care_about_error)
{
if (!care_about_error)
{
return NULL;
}
else
{
g_assert_not_reached ();
}
}

return out;
}

static GSList *
get_all_encodings ()
{
GSList *encs = NULL;
gint i = 0;

while (TRUE)
{
const XedEncoding *enc;

enc = xed_encoding_get_from_index (i);

if (enc == NULL)
break;

encs = g_slist_prepend (encs, (gpointer)enc);
i++;
}

return encs;
}

static gchar *
do_test (const gchar *test_in,
const gchar *enc,
GSList *encodings,
gsize nread,
const XedEncoding **guessed)
{
XedDocument *doc;
GOutputStream *out;
GError *err = NULL;
GtkTextIter start, end;
gchar *text;

if (enc != NULL)
{
encodings = NULL;
encodings = g_slist_prepend (encodings, (gpointer)xed_encoding_get_from_charset (enc));
}

doc = xed_document_new ();
encodings = g_slist_prepend (encodings, (gpointer)xed_encoding_get_utf8 ());
out = xed_document_output_stream_new (doc, encodings);

g_output_stream_write (out, test_in, nread, NULL, &err);
g_assert_no_error (err);

g_output_stream_flush (out, NULL, &err);
g_assert_no_error (err);

g_output_stream_close (out, NULL, &err);
g_assert_no_error (err);

if (guessed != NULL)
*guessed = xed_document_output_stream_get_guessed (XED_DOCUMENT_OUTPUT_STREAM (out));

gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &start, &end);
text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (doc),
&start,
&end,
FALSE);

g_object_unref (doc);
g_object_unref (out);

return text;
}

static void
test_utf8_utf8 ()
{
gchar *aux;

aux = do_test (TEXT_TO_CONVERT, "UTF-8", NULL, strlen (TEXT_TO_CONVERT), NULL);
g_assert_cmpstr (aux, ==, TEXT_TO_CONVERT);

aux = do_test ("foobar\xc3\xa8\xc3\xa8\xc3\xa8zzzzzz", "UTF-8", NULL, 18, NULL);
g_assert_cmpstr (aux, ==, "foobar\xc3\xa8\xc3\xa8\xc3\xa8zzzzzz");

aux = do_test ("foobar\xc3\xa8\xc3\xa8\xc3\xa8zzzzzz", "UTF-8", NULL, 12, NULL);
g_assert_cmpstr (aux, ==, "foobar\xc3\xa8\xc3\xa8\xc3\xa8");

/* FIXME: Use the utf8 stream for a fallback? */
//do_test_with_error ("\xef\xbf\xbezzzzzz", encs, G_IO_ERROR_FAILED);
}

static void
test_empty_conversion ()
{
const XedEncoding *guessed;
gchar *out;
GSList *encodings = NULL;

/* testing the case of an empty file and list of encodings with no
utf-8. In this case, the smart converter cannot determine the right
encoding (because there is no input), but should still default to
utf-8 for the detection */
encodings = g_slist_prepend (encodings, (gpointer)xed_encoding_get_from_charset ("UTF-16"));
encodings = g_slist_prepend (encodings, (gpointer)xed_encoding_get_from_charset ("ISO-8859-15"));

out = do_test ("", NULL, encodings, 0, &guessed);

g_assert_cmpstr (out, ==, "");

g_assert (guessed == xed_encoding_get_utf8 ());
}

static void
test_guessed ()
{
GSList *encs = NULL;
gchar *aux, *aux2, *fail;
gsize aux_len, fail_len;
const XedEncoding *guessed;

aux = get_encoded_text (TEXT_TO_GUESS, -1,
xed_encoding_get_from_charset ("UTF-16"),
xed_encoding_get_from_charset ("UTF-8"),
&aux_len,
TRUE);

fail = get_encoded_text (aux, aux_len,
xed_encoding_get_from_charset ("UTF-8"),
xed_encoding_get_from_charset ("ISO-8859-15"),
&fail_len,
FALSE);

g_assert (fail == NULL);

/* ISO-8859-15 should fail */
encs = g_slist_append (encs, (gpointer)xed_encoding_get_from_charset ("ISO-8859-15"));
encs = g_slist_append (encs, (gpointer)xed_encoding_get_from_charset ("UTF-16"));

aux2 = do_test (aux, NULL, encs, aux_len, &guessed);

g_assert (guessed == xed_encoding_get_from_charset ("UTF-16"));
}

int main (int argc,
char *argv[])
{
g_test_init (&argc, &argv, NULL);

g_test_add_func ("/document-output-stream/empty", test_empty);

g_test_add_func ("/document-output-stream/consecutive", test_consecutive);
g_test_add_func ("/document-output-stream/consecutive_tnewline", test_consecutive_tnewline);
g_test_add_func ("/document-output-stream/big-char", test_big_char);

g_test_add_func ("/document-output-stream/smart conversion: utf8-utf8", test_utf8_utf8);
g_test_add_func ("/document-output-stream/smart conversion: guessed", test_guessed);
g_test_add_func ("/document-output-stream/smart conversion: empty", test_empty_conversion);

return g_test_run ();
}

+ 0
- 722
tests/document-saver.c View File

@@ -1,722 +0,0 @@
/*
* document-saver.c
* This file is part of xed
*
* Copyright (C) 2010 - Jesse van den Kieboom
*
* xed is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* xed 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 xed; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/

#include "xed-document-loader.h"
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <string.h>
#include <sys/stat.h>

#define DEFAULT_LOCAL_URI "/tmp/xed-document-saver-test.txt"
#define DEFAULT_REMOTE_URI "sftp://localhost/tmp/xed-document-saver-test.txt"
#define DEFAULT_CONTENT "hello world!"
#define DEFAULT_CONTENT_RESULT "hello world!\n"

#define UNOWNED_LOCAL_DIRECTORY "/tmp/xed-document-saver-unowned"
#define UNOWNED_LOCAL_URI "/tmp/xed-document-saver-unowned/xed-document-saver-test.txt"

#define UNOWNED_REMOTE_DIRECTORY "sftp://localhost/tmp/xed-document-saver-unowned"
#define UNOWNED_REMOTE_URI "sftp://localhost/tmp/xed-document-saver-unowned/xed-document-saver-test.txt"

#define UNOWNED_GROUP_LOCAL_URI "/tmp/xed-document-saver-unowned-group.txt"
#define UNOWNED_GROUP_REMOTE_URI "sftp://localhost/tmp/xed-document-saver-unowned-group.txt"

static gboolean test_completed;
static gboolean mount_completed;
static gboolean mount_success;

typedef struct
{
gchar *uri;
const gchar *test_contents;
gpointer data;
} SaverTestData;

static SaverTestData *
saver_test_data_new (const gchar *uri, const gchar *test_contents, gpointer data)
{
SaverTestData *ret = g_slice_new (SaverTestData);

ret->uri = g_strdup (uri);
ret->test_contents = test_contents;
ret->data = data;

return ret;
}

static void
saver_test_data_free (SaverTestData *data)
{
if (data == NULL)
{
return;
}

g_free (data->uri);
g_slice_free (SaverTestData, data);
}

static XedDocument *
create_document (const gchar *contents)
{
XedDocument *document = xed_document_new ();

gtk_text_buffer_set_text (GTK_TEXT_BUFFER (document), contents, -1);
return document;
}

static void
complete_test_error (XedDocument *document,
GError *error,
SaverTestData *data)
{
g_assert_no_error (error);
}

static const gchar *
read_file (const gchar *uri)
{
GFile *file = g_file_new_for_commandline_arg (uri);
GError *error = NULL;
static gchar buffer[4096];
gsize read;

GInputStream *stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));

g_assert_no_error (error);

g_input_stream_read_all (stream, buffer, sizeof (buffer) - 1, &read, NULL, &error);
g_assert_no_error (error);

buffer[read] = '\0';

g_input_stream_close (stream, NULL, NULL);

g_object_unref (stream);
g_object_unref (file);

return buffer;
}

static void
complete_test (XedDocument *document,
GError *error,
SaverTestData *data)
{
test_completed = TRUE;

if (data && data->test_contents && data->uri)
{
g_assert_cmpstr (data->test_contents, ==, read_file (data->uri));
}
}

static void
mount_ready_callback (GObject *object,
GAsyncResult *result,
gpointer data)
{
GError *error = NULL;
mount_success = g_file_mount_enclosing_volume_finish (G_FILE (object),
result,
&error);

if (error && error->code == G_IO_ERROR_ALREADY_MOUNTED)
{
mount_success = TRUE;
g_error_free (error);
}
else
{
g_assert_no_error (error);
}

mount_completed = TRUE;
}

static gboolean
ensure_mounted (GFile *file)
{
GMountOperation *mo;

mount_success = FALSE;
mount_completed = FALSE;

if (g_file_is_native (file))
{
return TRUE;
}

mo = gtk_mount_operation_new (NULL);

g_file_mount_enclosing_volume (file,
G_MOUNT_MOUNT_NONE,
mo,
NULL,
mount_ready_callback,
NULL);

while (!mount_completed)
{
g_main_context_iteration (NULL, TRUE);
}

g_object_unref (mo);

return mount_success;
}

static void
test_saver (const gchar *filename_or_uri,
const gchar *contents,
XedDocumentNewlineType newline_type,
XedDocumentSaveFlags save_flags,
GCallback saved_callback,
SaverTestData *data)
{
GFile *file;
gchar *uri;
XedDocument *document;
gboolean existed;

document = create_document (contents);
xed_document_set_newline_type (document, newline_type);

g_signal_connect (document, "saved", G_CALLBACK (complete_test_error), data);

if (saved_callback)
{
g_signal_connect (document, "saved", saved_callback, data);
}

g_signal_connect_after (document, "saved", G_CALLBACK (complete_test), data);

test_completed = FALSE;

file = g_file_new_for_commandline_arg (filename_or_uri);
existed = g_file_query_exists (file, NULL);

ensure_mounted (file);

xed_document_save_as (document, file, xed_encoding_get_utf8 (), save_flags);

while (!test_completed)
{
g_main_context_iteration (NULL, TRUE);
}

if (!existed)
{
g_file_delete (file, NULL, NULL);
}

g_object_unref (file);

saver_test_data_free (data);
}

typedef struct
{
XedDocumentNewlineType type;
const gchar *text;
const gchar *result;
} NewLineTestData;

static NewLineTestData newline_test_data[] = {
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\nhello\nworld", "\nhello\nworld\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\nhello\nworld\n", "\nhello\nworld\n\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\nhello\nworld\n\n", "\nhello\nworld\n\n\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\r\nhello\r\nworld", "\nhello\nworld\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\r\nhello\r\nworld\r\n", "\nhello\nworld\n\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\rhello\rworld", "\nhello\nworld\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\rhello\rworld\r", "\nhello\nworld\n\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\nhello\r\nworld", "\nhello\nworld\n"},
{XED_DOCUMENT_NEWLINE_TYPE_LF, "\nhello\r\nworld\r", "\nhello\nworld\n\n"},

{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\nhello\nworld", "\r\nhello\r\nworld\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\nhello\nworld\n", "\r\nhello\r\nworld\r\n\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\nhello\nworld\n\n", "\r\nhello\r\nworld\r\n\r\n\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\r\nhello\r\nworld", "\r\nhello\r\nworld\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\r\nhello\r\nworld\r\n", "\r\nhello\r\nworld\r\n\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\rhello\rworld", "\r\nhello\r\nworld\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\rhello\rworld\r", "\r\nhello\r\nworld\r\n\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\nhello\r\nworld", "\r\nhello\r\nworld\r\n"},
{XED_DOCUMENT_NEWLINE_TYPE_CR_LF, "\nhello\r\nworld\r", "\r\nhello\r\nworld\r\n\r\n"},

{XED_DOCUMENT_NEWLINE_TYPE_CR, "\nhello\nworld", "\rhello\rworld\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\nhello\nworld\n", "\rhello\rworld\r\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\nhello\nworld\n\n", "\rhello\rworld\r\r\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\r\nhello\r\nworld", "\rhello\rworld\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\r\nhello\r\nworld\r\n", "\rhello\rworld\r\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\rhello\rworld", "\rhello\rworld\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\rhello\rworld\r", "\rhello\rworld\r\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\nhello\r\nworld", "\rhello\rworld\r"},
{XED_DOCUMENT_NEWLINE_TYPE_CR, "\nhello\r\nworld\r", "\rhello\rworld\r\r"}
};

static void
test_new_line (const gchar *filename, XedDocumentSaveFlags save_flags)
{
gint i;
gint num = sizeof (newline_test_data) / sizeof (NewLineTestData);

for (i = 0; i < num; ++i)
{
NewLineTestData *nt = &(newline_test_data[i]);

test_saver (filename,
nt->text,
nt->type,
save_flags,
NULL,
saver_test_data_new (filename, nt->result, NULL));
}
}

static void
test_local_newline ()
{
test_new_line (DEFAULT_LOCAL_URI, 0);
}

static void
test_local ()
{
test_saver (DEFAULT_LOCAL_URI,
"hello world",
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (DEFAULT_LOCAL_URI, "hello world\n", NULL));

test_saver (DEFAULT_LOCAL_URI,
"hello world\r\n",
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (DEFAULT_LOCAL_URI, "hello world\n\n", NULL));

test_saver (DEFAULT_LOCAL_URI,
"hello world\n",
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (DEFAULT_LOCAL_URI, "hello world\n\n", NULL));
}

static void
test_remote_newline ()
{
test_new_line (DEFAULT_REMOTE_URI, 0);
}

static void
test_remote ()
{
test_saver (DEFAULT_REMOTE_URI,
"hello world",
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (DEFAULT_REMOTE_URI, "hello world\n", NULL));

test_saver (DEFAULT_REMOTE_URI,
"hello world\r\n",
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (DEFAULT_REMOTE_URI, "hello world\n\n", NULL));

test_saver (DEFAULT_REMOTE_URI,
"hello world\n",
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (DEFAULT_REMOTE_URI, "hello world\n\n", NULL));
}

static void
check_permissions (GFile *file,
guint permissions)
{
GError *error = NULL;
GFileInfo *info;

info = g_file_query_info (file,
G_FILE_ATTRIBUTE_UNIX_MODE,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);

g_assert_no_error (error);

g_assert_cmpint (permissions,
==,
g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & ACCESSPERMS);

g_object_unref (info);
}

static void
check_permissions_saved (XedDocument *document,
GError *error,
SaverTestData *data)
{
guint permissions = (guint)GPOINTER_TO_INT (data->data);
GFile *file = xed_document_get_location (document);

check_permissions (file, permissions);

g_object_unref (file);
}

static void
test_permissions (const gchar *uri,
guint permissions)
{
GError *error = NULL;
GFile *file = g_file_new_for_commandline_arg (uri);
GFileOutputStream *stream;
GFileInfo *info;
guint mode;

g_file_delete (file, NULL, NULL);
stream = g_file_create (file, 0, NULL, &error);

g_assert_no_error (error);

g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
g_object_unref (stream);

info = g_file_query_info (file,
G_FILE_ATTRIBUTE_UNIX_MODE,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);

g_assert_no_error (error);

mode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
g_object_unref (info);

g_file_set_attribute_uint32 (file,
G_FILE_ATTRIBUTE_UNIX_MODE,
(mode & ~ACCESSPERMS) | permissions,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);
g_assert_no_error (error);

check_permissions (file, permissions);

test_saver (uri,
DEFAULT_CONTENT,
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
G_CALLBACK (check_permissions_saved),
saver_test_data_new (uri,
DEFAULT_CONTENT_RESULT,
GINT_TO_POINTER ((gint)permissions)));

g_file_delete (file, NULL, NULL);
g_object_unref (file);
}

static void
test_local_permissions ()
{
test_permissions (DEFAULT_LOCAL_URI, 0600);
test_permissions (DEFAULT_LOCAL_URI, 0660);
test_permissions (DEFAULT_LOCAL_URI, 0666);
test_permissions (DEFAULT_LOCAL_URI, 0760);
}

static void
test_local_unowned_directory ()
{
test_saver (UNOWNED_LOCAL_URI,
DEFAULT_CONTENT,
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (UNOWNED_LOCAL_URI,
DEFAULT_CONTENT_RESULT,
NULL));
}

static void
test_remote_unowned_directory ()
{
test_saver (UNOWNED_REMOTE_URI,
DEFAULT_CONTENT,
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
NULL,
saver_test_data_new (UNOWNED_REMOTE_URI,
DEFAULT_CONTENT_RESULT,
NULL));
}

static void
test_remote_permissions ()
{
test_permissions (DEFAULT_REMOTE_URI, 0600);
test_permissions (DEFAULT_REMOTE_URI, 0660);
test_permissions (DEFAULT_REMOTE_URI, 0666);
test_permissions (DEFAULT_REMOTE_URI, 0760);
}

static void
test_unowned_group_permissions (XedDocument *document,
GError *error,
SaverTestData *data)
{
GFile *file = g_file_new_for_commandline_arg (data->uri);
GError *err = NULL;
const gchar *group;
guint32 mode;

GFileInfo *info = g_file_query_info (file,
G_FILE_ATTRIBUTE_OWNER_GROUP ","
G_FILE_ATTRIBUTE_UNIX_MODE,
G_FILE_QUERY_INFO_NONE,
NULL,
&err);

g_assert_no_error (err);

group = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP);
g_assert_cmpstr (group, ==, "root");

mode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);

g_assert_cmpint (mode & ACCESSPERMS, ==, 0660);

g_object_unref (file);
g_object_unref (info);
}

static void
test_unowned_group (const gchar *uri)
{
test_saver (uri,
DEFAULT_CONTENT,
XED_DOCUMENT_NEWLINE_TYPE_LF,
0,
G_CALLBACK (test_unowned_group_permissions),
saver_test_data_new (uri,
DEFAULT_CONTENT_RESULT,
NULL));
}

static void
test_local_unowned_group ()
{
test_unowned_group (UNOWNED_GROUP_LOCAL_URI);
}

static void
test_remote_unowned_group ()
{
test_unowned_group (UNOWNED_GROUP_REMOTE_URI);
}

static gboolean
check_unowned_directory ()
{
GFile *unowned = g_file_new_for_path (UNOWNED_LOCAL_DIRECTORY);
GFile *unowned_file;
GFileInfo *info;
GError *error = NULL;

g_printf ("*** Checking for unowned directory test... ");

info = g_file_query_info (unowned,
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);

if (error)
{
g_object_unref (unowned);
g_printf ("NO: directory does not exist\n");

g_error_free (error);
return FALSE;
}

if (g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
{
g_object_unref (unowned);

g_printf ("NO: directory is writable\n");
g_object_unref (info);
return FALSE;
}

g_object_unref (info);
g_object_unref (unowned);

unowned_file = g_file_new_for_commandline_arg (UNOWNED_LOCAL_URI);

info = g_file_query_info (unowned_file,
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);

if (error)
{
g_object_unref (unowned_file);
g_error_free (error);

g_printf ("NO: file does not exist\n");
return FALSE;
}

if (!g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
{
g_object_unref (unowned_file);

g_printf ("NO: file is not writable\n");
g_object_unref (info);
return FALSE;
}

g_object_unref (info);
g_object_unref (unowned_file);

g_printf ("YES\n");
return TRUE;
}

static gboolean
check_unowned_group ()
{
GFile *unowned = g_file_new_for_path (UNOWNED_GROUP_LOCAL_URI);
GFileInfo *info;
GError *error = NULL;