1 /* SPDX-FileCopyrightText: 2016-2020 - Sébastien Wilmet <swilmet@gnome.org>
2  * SPDX-License-Identifier: LGPL-3.0-or-later
3  */
4 
5 #include "config.h"
6 #include <tepl/tepl.h>
7 #include <glib/gi18n-lib.h>
8 #include "tepl-test-utils.h"
9 
10 static void
check_short_name(TeplFile * file,const gchar * expected_short_name)11 check_short_name (TeplFile    *file,
12 		  const gchar *expected_short_name)
13 {
14 	gchar *received_short_name;
15 
16 	received_short_name = tepl_file_get_short_name (file);
17 	g_assert_cmpstr (received_short_name, ==, expected_short_name);
18 	g_free (received_short_name);
19 }
20 
21 static void
check_short_name_is_untitled_file_number(TeplFile * file,gint untitled_number)22 check_short_name_is_untitled_file_number (TeplFile *file,
23 					  gint      untitled_number)
24 {
25 	gchar *expected_short_name;
26 
27 	/* For the translation it needs to be the exact same string as in the
28 	 * TeplFile implementation, to be able to run the unit test with any
29 	 * locale.
30 	 */
31 	expected_short_name = g_strdup_printf (_("Untitled File %d"), untitled_number);
32 	check_short_name (file, expected_short_name);
33 	g_free (expected_short_name);
34 }
35 
36 static void
test_untitled_files(void)37 test_untitled_files (void)
38 {
39 	TeplFile *file1;
40 	TeplFile *file2;
41 	TeplFile *file3;
42 	GFile *location;
43 
44 	file1 = tepl_file_new ();
45 	check_short_name_is_untitled_file_number (file1, 1);
46 
47 	file2 = tepl_file_new ();
48 	check_short_name_is_untitled_file_number (file2, 2);
49 
50 	/* Release an untitled number by destroying a file. */
51 	g_object_unref (file1);
52 	check_short_name_is_untitled_file_number (file2, 2); // still the same.
53 	file1 = tepl_file_new ();
54 	check_short_name_is_untitled_file_number (file1, 1);
55 
56 	/* Release an untitled number by setting a location. */
57 	location = g_file_new_for_path ("location");
58 	tepl_file_set_location (file1, location);
59 	check_short_name_is_untitled_file_number (file2, 2); // still the same.
60 	file3 = tepl_file_new ();
61 	check_short_name_is_untitled_file_number (file3, 1);
62 
63 	/* Reset location to NULL. */
64 	tepl_file_set_location (file1, NULL);
65 	check_short_name_is_untitled_file_number (file1, 3);
66 
67 	g_object_unref (file1);
68 	g_object_unref (file2);
69 	g_object_unref (file3);
70 	g_object_unref (location);
71 }
72 
73 static void
test_short_name(void)74 test_short_name (void)
75 {
76 	TeplFile *file;
77 	GFile *location;
78 	TeplWaitSignalData *data;
79 	GError *error = NULL;
80 
81 	location = g_file_new_build_filename (g_get_tmp_dir (), "tepl-test-file", NULL);
82 
83 	/* Get the fallback short-name, for a file that doesn't exist. */
84 	g_file_delete (location, NULL, &error);
85 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
86 	{
87 		g_clear_error (&error);
88 	}
89 	g_assert_no_error (error);
90 
91 	file = tepl_file_new ();
92 	data = _tepl_test_utils_wait_signal_setup (G_OBJECT (file), "notify::short-name");
93 	tepl_file_set_location (file, location);
94 	_tepl_test_utils_wait_signal (data);
95 	check_short_name (file, "tepl-test-file");
96 	g_object_unref (file);
97 
98 	/* Get the display-name for a local file (so the file must exist). */
99 	_tepl_test_utils_set_file_content (location, "file content");
100 
101 	file = tepl_file_new ();
102 	data = _tepl_test_utils_wait_signal_setup (G_OBJECT (file), "notify::short-name");
103 	tepl_file_set_location (file, location);
104 	_tepl_test_utils_wait_signal (data);
105 	check_short_name (file, "tepl-test-file");
106 	g_object_unref (file);
107 	g_object_unref (location);
108 
109 	/* Test the special case for a remote location that has no parent GFile. */
110 	location = g_file_new_for_uri ("https://swilmet.be");
111 	file = tepl_file_new ();
112 	data = _tepl_test_utils_wait_signal_setup (G_OBJECT (file), "notify::short-name");
113 	tepl_file_set_location (file, location);
114 	_tepl_test_utils_wait_signal (data);
115 	check_short_name (file, "https://swilmet.be");
116 	g_object_unref (file);
117 	g_object_unref (location);
118 
119 	// It's not really important if the trailing slash is still present or
120 	// not in the short-name, but test it anyway. The important thing is to
121 	// have the https://swilmet.be prefix, with an optional trailing slash.
122 	location = g_file_new_for_uri ("https://swilmet.be/");
123 	file = tepl_file_new ();
124 	data = _tepl_test_utils_wait_signal_setup (G_OBJECT (file), "notify::short-name");
125 	tepl_file_set_location (file, location);
126 	_tepl_test_utils_wait_signal (data);
127 	check_short_name (file, "https://swilmet.be/");
128 	g_object_unref (file);
129 	g_object_unref (location);
130 }
131 
132 #if 0
133 static void
134 sleep_for_one_second (void)
135 {
136 	g_usleep (G_USEC_PER_SEC);
137 }
138 
139 static void
140 load_cb (GObject      *source_object,
141 	 GAsyncResult *result,
142 	 gpointer      user_data)
143 {
144 	TeplFileLoader *loader = TEPL_FILE_LOADER (source_object);
145 	GError *error = NULL;
146 
147 	tepl_file_loader_load_finish (loader, result, &error);
148 	g_assert_no_error (error);
149 
150 	gtk_main_quit ();
151 }
152 
153 static void
154 load (TeplBuffer *buffer)
155 {
156 	TeplFile *file;
157 	TeplFileLoader *loader;
158 
159 	file = tepl_buffer_get_file (buffer);
160 
161 	loader = tepl_file_loader_new (buffer, file);
162 	tepl_file_loader_load_async (loader,
163 				     G_PRIORITY_DEFAULT,
164 				     NULL, /* cancellable */
165 				     NULL, NULL, NULL, /* progress cb */
166 				     load_cb,
167 				     NULL);
168 
169 	gtk_main ();
170 	g_object_unref (loader);
171 }
172 
173 static void
174 save_cb (GObject      *source_object,
175 	 GAsyncResult *result,
176 	 gpointer      user_data)
177 {
178 	TeplFileSaver *saver = TEPL_FILE_SAVER (source_object);
179 	gboolean expect_externally_modified_error = GPOINTER_TO_INT (user_data);
180 	GError *error = NULL;
181 
182 	tepl_file_saver_save_finish (saver, result, &error);
183 	if (expect_externally_modified_error)
184 	{
185 		g_assert_true (g_error_matches (error,
186 						TEPL_FILE_SAVER_ERROR,
187 						TEPL_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED));
188 		g_clear_error (&error);
189 	}
190 	else
191 	{
192 		g_assert_no_error (error);
193 	}
194 
195 	gtk_main_quit ();
196 }
197 
198 static void
199 save (TeplBuffer *buffer,
200       gboolean    expect_externally_modified_error)
201 {
202 	TeplFile *file;
203 	TeplFileSaver *saver;
204 
205 	file = tepl_buffer_get_file (buffer);
206 
207 	saver = tepl_file_saver_new (buffer, file);
208 	tepl_file_saver_save_async (saver,
209 				    G_PRIORITY_DEFAULT,
210 				    NULL, /* cancellable */
211 				    NULL, NULL, NULL, /* progress cb */
212 				    save_cb,
213 				    GINT_TO_POINTER (expect_externally_modified_error));
214 
215 	gtk_main ();
216 
217 	if (expect_externally_modified_error)
218 	{
219 		expect_externally_modified_error = FALSE;
220 
221 		tepl_file_saver_set_flags (saver, TEPL_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME);
222 		tepl_file_saver_save_async (saver,
223 					    G_PRIORITY_DEFAULT,
224 					    NULL, /* cancellable */
225 					    NULL, NULL, NULL, /* progress cb */
226 					    save_cb,
227 					    GINT_TO_POINTER (expect_externally_modified_error));
228 
229 		gtk_main ();
230 	}
231 
232 	g_object_unref (saver);
233 }
234 
235 static void
236 save_as (TeplBuffer *buffer,
237 	 GFile      *new_location)
238 {
239 	TeplFile *file;
240 	TeplFileSaver *saver;
241 	gboolean expect_externally_modified_error = FALSE;
242 
243 	file = tepl_buffer_get_file (buffer);
244 
245 	saver = tepl_file_saver_new_with_target (buffer, file, new_location);
246 	tepl_file_saver_save_async (saver,
247 				    G_PRIORITY_DEFAULT,
248 				    NULL, /* cancellable */
249 				    NULL, NULL, NULL, /* progress cb */
250 				    save_cb,
251 				    GINT_TO_POINTER (expect_externally_modified_error));
252 
253 	gtk_main ();
254 	g_object_unref (saver);
255 }
256 
257 static void
258 test_externally_modified (void)
259 {
260 	TeplBuffer *buffer;
261 	TeplFile *file;
262 	gchar *path;
263 	gchar *new_path;
264 	GFile *location;
265 	GFile *new_location;
266 	GError *error = NULL;
267 
268 	buffer = tepl_buffer_new ();
269 	file = tepl_buffer_get_file (buffer);
270 
271 	/* With NULL location */
272 	g_assert_true (!tepl_file_is_externally_modified (file));
273 	tepl_file_check_file_on_disk (file);
274 	g_assert_true (!tepl_file_is_externally_modified (file));
275 
276 	/* Set location, but not yet loaded or saved */
277 	path = g_build_filename (g_get_tmp_dir (), "tepl-test-file", NULL);
278 	g_file_set_contents (path, "a", -1, &error);
279 	g_assert_no_error (error);
280 
281 	location = g_file_new_for_path (path);
282 	tepl_file_set_location (file, location);
283 	g_assert_true (!tepl_file_is_externally_modified (file));
284 	tepl_file_check_file_on_disk (file);
285 	g_assert_true (!tepl_file_is_externally_modified (file));
286 
287 	/* Load */
288 	load (buffer);
289 	g_assert_true (!tepl_file_is_externally_modified (file));
290 	tepl_file_check_file_on_disk (file);
291 	g_assert_true (!tepl_file_is_externally_modified (file));
292 
293 	/* Save */
294 	save (buffer, FALSE);
295 	g_assert_true (!tepl_file_is_externally_modified (file));
296 	tepl_file_check_file_on_disk (file);
297 	g_assert_true (!tepl_file_is_externally_modified (file));
298 
299 	/* Modify externally and then save.
300 	 * Sleep one second to force the timestamp/etag to change.
301 	 */
302 	sleep_for_one_second ();
303 	g_file_set_contents (path, "b", -1, &error);
304 	g_assert_no_error (error);
305 	tepl_file_check_file_on_disk (file);
306 	g_assert_true (tepl_file_is_externally_modified (file));
307 
308 	save (buffer, TRUE);
309 	g_assert_true (!tepl_file_is_externally_modified (file));
310 	tepl_file_check_file_on_disk (file);
311 	g_assert_true (!tepl_file_is_externally_modified (file));
312 
313 	/* Modify externally and then load */
314 	sleep_for_one_second ();
315 	g_file_set_contents (path, "c", -1, &error);
316 	g_assert_no_error (error);
317 	tepl_file_check_file_on_disk (file);
318 	g_assert_true (tepl_file_is_externally_modified (file));
319 
320 	load (buffer);
321 	g_assert_true (!tepl_file_is_externally_modified (file));
322 	tepl_file_check_file_on_disk (file);
323 	g_assert_true (!tepl_file_is_externally_modified (file));
324 
325 	/* Modify externally and then save as */
326 	sleep_for_one_second ();
327 	g_file_set_contents (path, "d", -1, &error);
328 	g_assert_no_error (error);
329 	tepl_file_check_file_on_disk (file);
330 	g_assert_true (tepl_file_is_externally_modified (file));
331 
332 	new_path = g_build_filename (g_get_tmp_dir (), "tepl-test-file-2", NULL);
333 	g_file_set_contents (new_path, "e", -1, &error);
334 	g_assert_no_error (error);
335 
336 	new_location = g_file_new_for_path (new_path);
337 	save_as (buffer, new_location);
338 	g_assert_true (g_file_equal (new_location, tepl_file_get_location (file)));
339 	g_assert_true (!tepl_file_is_externally_modified (file));
340 	tepl_file_check_file_on_disk (file);
341 	g_assert_true (!tepl_file_is_externally_modified (file));
342 
343 	/* Modify externally and then save as to same location */
344 	sleep_for_one_second ();
345 	g_file_set_contents (new_path, "f", -1, &error);
346 	g_assert_no_error (error);
347 	tepl_file_check_file_on_disk (file);
348 	g_assert_true (tepl_file_is_externally_modified (file));
349 
350 	g_assert_true (g_file_equal (new_location, tepl_file_get_location (file)));
351 	save_as (buffer, new_location);
352 	g_assert_true (!tepl_file_is_externally_modified (file));
353 	tepl_file_check_file_on_disk (file);
354 	g_assert_true (!tepl_file_is_externally_modified (file));
355 
356 	/* Cleanup */
357 	g_file_delete (location, NULL, &error);
358 	g_assert_no_error (error);
359 	g_file_delete (new_location, NULL, &error);
360 	g_assert_no_error (error);
361 
362 	g_free (path);
363 	g_free (new_path);
364 	g_object_unref (location);
365 	g_object_unref (new_location);
366 	g_object_unref (buffer);
367 }
368 #endif
369 
370 int
main(int argc,char ** argv)371 main (int    argc,
372       char **argv)
373 {
374 	gtk_test_init (&argc, &argv);
375 
376 	g_test_add_func ("/file/untitled_files", test_untitled_files);
377 	g_test_add_func ("/file/short_name", test_short_name);
378 
379 #if 0
380 	g_test_add_func ("/file/externally_modified", test_externally_modified);
381 #endif
382 
383 	return g_test_run ();
384 }
385