1 /*
2  * test_engine_ngspice.c
3  *
4  *
5  * Authors:
6  *  Michi <st101564@stud.uni-stuttgart.de>
7  *
8  * Web page: https://ahoi.io/project/oregano
9  *
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of the
14  * License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this program; if not, write to the
23  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26 
27 #include "../src/engines/ngspice-watcher.h"
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 #include <glib/gprintf.h>
31 
32 static void test_engine_ngspice_basic();
33 static void test_engine_ngspice_error_no_such_file_or_directory();
34 static void test_engine_ngspice_error_step_zero();
35 
36 void
add_funcs_test_engine_ngspice()37 add_funcs_test_engine_ngspice() {
38 	g_test_add_func ("/core/engine/ngspice/watcher/basic", test_engine_ngspice_basic);
39 	g_test_add_func ("/core/engine/ngspice/watcher/error/no_such_file_or_directory", test_engine_ngspice_error_no_such_file_or_directory);
40 	g_test_add_func ("/core/engine/ngspice/watcher/error/step_zero", test_engine_ngspice_error_step_zero);
41 }
42 
test_engine_ngspice_log_append_error(GList ** list,const gchar * string)43 static void test_engine_ngspice_log_append_error(GList **list, const gchar *string) {
44 	*list = g_list_append(*list, g_strdup(string));
45 }
46 
print_log(const GList * list)47 static void print_log(const GList *list) {
48 	for (const GList *walker = list; walker; walker = walker->next)
49 		g_printf("%s", (char *)walker->data);
50 }
51 
52 typedef struct {
53 	NgspiceWatcherBuildAndLaunchResources *resources;
54 	OreganoNgSpice *ngspice;
55 	GMainLoop *loop;
56 	GList *log_list;
57 	SimSettings *sim_settings;
58 } TestEngineNgspiceResources;
59 
test_engine_ngspice_resources_new()60 static TestEngineNgspiceResources *test_engine_ngspice_resources_new() {
61 	TestEngineNgspiceResources *test_resources = g_new0(TestEngineNgspiceResources, 1);
62 
63 
64 	test_resources->resources = g_new0(NgspiceWatcherBuildAndLaunchResources, 1);
65 	NgspiceWatcherBuildAndLaunchResources *resources = test_resources->resources;
66 	test_resources->ngspice = OREGANO_NGSPICE(oregano_spice_new(NULL, FALSE));
67 	OreganoNgSpice *ngspice = test_resources->ngspice;
68 	GMainLoop *loop = g_main_loop_new(NULL, FALSE);
69 	test_resources->loop = loop;
70 	g_signal_connect_swapped(G_OBJECT(ngspice), "done", G_CALLBACK(g_main_loop_quit), loop);
71 	g_signal_connect_swapped(G_OBJECT(ngspice), "aborted", G_CALLBACK(g_main_loop_quit), loop);
72 
73 	resources->aborted = &ngspice->priv->aborted;
74 	resources->analysis = &ngspice->priv->analysis;
75 	resources->child_pid = &ngspice->priv->child_pid;
76 	resources->current = &ngspice->priv->current;
77 	resources->emit_instance = ngspice;
78 
79 	resources->log.log = (gpointer)&test_resources->log_list;
80 	resources->log.log_append = NULL;
81 	resources->log.log_append_error = (LogFunction)test_engine_ngspice_log_append_error;
82 
83 	resources->num_analysis = &ngspice->priv->num_analysis;
84 	resources->progress_ngspice = &ngspice->priv->progress_ngspice;
85 	resources->progress_reader = &ngspice->priv->progress_reader;
86 	test_resources->sim_settings = sim_settings_new(NULL);
87 	resources->sim_settings = test_resources->sim_settings;
88 	resources->netlist_file = g_strdup("/tmp/netlist.tmp");
89 	resources->ngspice_result_file = g_strdup("/tmp/netlist.lst");
90 
91 	resources->cancel_info = ngspice->priv->cancel_info;
92 	cancel_info_subscribe(resources->cancel_info);
93 
94 	return test_resources;
95 }
96 
test_engine_ngspice_resources_finalize(TestEngineNgspiceResources * test_resources)97 static void test_engine_ngspice_resources_finalize(TestEngineNgspiceResources *test_resources) {
98 	NgspiceWatcherBuildAndLaunchResources *resources = test_resources->resources;
99 
100 	g_main_loop_unref(test_resources->loop);
101 
102 	sim_settings_finalize(test_resources->sim_settings);
103 	g_object_unref(test_resources->ngspice);
104 
105 	g_list_free_full(test_resources->log_list, g_free);
106 
107 	ngspice_watcher_build_and_launch_resources_finalize(resources);
108 }
109 
test_engine_ngspice_basic()110 static void test_engine_ngspice_basic() {
111 
112 	TestEngineNgspiceResources *test_resources = test_engine_ngspice_resources_new();
113 
114 	g_autofree gchar *test_dir = get_test_base_dir();
115 
116 	g_free(test_resources->resources->netlist_file);
117 	test_resources->resources->netlist_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/basic/input.netlist", test_dir);
118 
119 	g_free(test_resources->resources->ngspice_result_file);
120 	test_resources->resources->ngspice_result_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/basic/result/actual.txt", test_dir);
121 
122 	g_autofree gchar *actual_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/basic/result/actual.txt", test_dir);
123 	g_autofree gchar *expected_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/basic/result/expected.txt", test_dir);
124 
125 	ngspice_watcher_build_and_launch(test_resources->resources);
126 	g_main_loop_run(test_resources->loop);
127 	print_log(test_resources->log_list);
128 
129 	test_engine_ngspice_resources_finalize(test_resources);
130 
131 	g_autofree gchar *actual_content = NULL;
132 	gsize actual_size;
133 	g_file_get_contents(actual_file, &actual_content, &actual_size, NULL);
134 
135 	g_autofree gchar *expected_content = NULL;
136 	gsize expected_size;
137 	g_file_get_contents(expected_file, &expected_content, &expected_size, NULL);
138 
139 	// FIXME this comparision is too cumbersome and error prone
140 	// any kind of change in the ngspice output will brake this
141 	// we should only compare the lines which are considered
142 	// number output of the simulation
143 	// g_assert_true(expected_size > 350);
144 	// g_assert_true(actual_size > expected_size - 350);
145 	// double distance = 0;
146 	// for (gsize i = 0; i < expected_size - 350; i++) {
147 	//	distance += ABS(actual_content[i] - expected_content[i]);
148 	// }
149 	// FIXME this will never work reliably
150 	// g_assert_true(distance < 3*16*20);
151 }
152 
test_engine_ngspice_error_no_such_file_or_directory()153 static void test_engine_ngspice_error_no_such_file_or_directory() {
154 	TestEngineNgspiceResources *test_resources = test_engine_ngspice_resources_new();
155 
156 	// make sure that the given file does not exist
157 	g_free(test_resources->resources->netlist_file);
158 	gint fd = g_file_open_tmp(NULL, &test_resources->resources->netlist_file, NULL);
159 	g_close(fd, NULL);
160 	g_remove(test_resources->resources->netlist_file);
161 
162 	ngspice_watcher_build_and_launch(test_resources->resources);
163 	g_main_loop_run(test_resources->loop);
164 
165 	g_assert_nonnull(test_resources->log_list);
166 	g_assert_true(g_str_has_suffix(test_resources->log_list->data, " No such file or directory\n"));
167 
168 	test_engine_ngspice_resources_finalize(test_resources);
169 }
170 
test_engine_ngspice_error_step_zero()171 static void test_engine_ngspice_error_step_zero() {
172 	TestEngineNgspiceResources *test_resources = test_engine_ngspice_resources_new();
173 
174 
175 	g_autofree gchar *test_dir = get_test_base_dir();
176 
177 	g_free(test_resources->resources->netlist_file);
178 	test_resources->resources->netlist_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/error/step_zero/input.netlist", test_dir);
179 
180 	g_free(test_resources->resources->ngspice_result_file);
181 	test_resources->resources->ngspice_result_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/error/step_zero/result/actual.txt", test_dir);
182 
183 	g_autofree gchar *actual_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/error/step_zero/result/actual.txt", test_dir);
184 	g_autofree gchar *expected_file = g_strdup_printf("%s/test-files/test_engine_ngspice_watcher/error/step_zero/result/expected.txt", test_dir);
185 
186 
187 	ngspice_watcher_build_and_launch(test_resources->resources);
188 	g_main_loop_run(test_resources->loop);
189 
190 	g_autofree gchar *actual_content = NULL;
191 	gsize actual_size;
192 	g_file_get_contents(actual_file, &actual_content, &actual_size, NULL);
193 
194 	g_autofree gchar *expected_content = NULL;
195 	gsize expected_size;
196 	g_file_get_contents(expected_file, &expected_content, &expected_size, NULL);
197 
198 	//
199 	// g_assert_cmpstr(actual_content, ==, expected_content);
200   //
201   // const gchar *array[] = {
202   // 			"\n",
203   // 			"ngspice stopped due to error, no simulation run!\n",
204   // 			"\n",
205   // 			"ERROR: fatal error in ngspice, exit(1)\n",
206   // 			"### ngspice exited abnormally ###\n",
207   // 			"### netlist error detected ###\n",
208   // 			"You made a mistake in the simulation settings or part properties.\n",
209   // 			"The following information will help you to analyze the error.\n",
210   // 			NULL
211   // 	};
212   //
213   // 	GList *walker = test_resources->log_list;
214   //
215   // 	for (int i = 0; array[i] != NULL; i++) {
216   // 		g_assert_nonnull(walker);
217   // 		g_assert_nonnull(walker->data);
218   // 		g_assert_cmpstr(walker->data, ==, array[i]);
219   // 		walker = walker->next;
220   // 	}
221 
222 	test_engine_ngspice_resources_finalize(test_resources);
223 }
224