Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_pretty.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
27#include "nilorea/n_common.h"
28#include "nilorea/n_log.h"
29#include "nilorea/n_pretty.h"
30#include "nilorea/n_str.h"
31
32#include <stdio.h>
33#include <string.h>
34#include <unistd.h>
35
36static int failures = 0;
37
38/* Parse the -V LOG_LEVEL verbosity argument. */
39static void process_args(int argc, char** argv) {
40 int opt = 0;
41 while ((opt = getopt(argc, argv, "hvV:")) != EOF) {
42 switch (opt) {
43 case 'V':
44 if (!strncmp("LOG_NULL", optarg, 8))
46 else if (!strncmp("LOG_NOTICE", optarg, 10))
48 else if (!strncmp("LOG_INFO", optarg, 8))
50 else if (!strncmp("LOG_ERR", optarg, 7))
52 else if (!strncmp("LOG_DEBUG", optarg, 9))
54 else {
55 fprintf(stderr, "Unknown log level %s\n", optarg);
56 exit(1);
57 }
58 break;
59 case 'v':
60 fprintf(stderr, "ex_pretty\n");
61 exit(1);
62 default:
63 fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
64 exit(1);
65 }
66 }
67}
68
69static void expect_true(const char* label, int cond) {
70 if (!cond) {
71 n_log(LOG_ERR, "%s: condition false", label);
72 failures++;
73 }
74}
75
76static void expect_contains(const char* label, const N_STR* out, const char* needle) {
77 if (!out || !out->data || !strstr(out->data, needle)) {
78 n_log(LOG_ERR, "%s: output does not contain '%s' (got: %s)",
79 label, needle, (out && out->data) ? out->data : "NULL");
80 failures++;
81 }
82}
83
84int main(int argc, char** argv) {
86 process_args(argc, argv);
87
88 /* JSON */
89 {
90 N_STR* out = n_pretty_json("{\"a\":1,\"b\":[true,null],\"c\":\"x\"}");
91 expect_true("json valid returns output", out != NULL);
92 expect_contains("json output is multi-line", out, "\n");
93 expect_contains("json key survives", out, "\"a\":");
94 free_nstr(&out);
95
96 out = n_pretty_json("this is not json");
97 expect_true("json garbage returns NULL", out == NULL);
98 free_nstr(&out);
99
100 out = n_pretty_json("{\"a\":");
101 expect_true("json truncated returns NULL", out == NULL);
102 free_nstr(&out);
103 }
104
105 /* XML / HTML */
106 {
107 N_STR* out = n_pretty_xml("<root><a x=\"1\"><b>hi</b></a></root>");
108 expect_true("xml valid returns output", out != NULL);
109 expect_contains("xml child is indented", out, "\n <a x=\"1\">\n");
110 expect_contains("xml grandchild is indented", out, "\n <b>\n");
111 expect_contains("xml text is indented", out, "\n hi\n");
112 expect_contains("xml close returns to depth", out, "\n</root>\n");
113 free_nstr(&out);
114
115 /* void element must not indent what follows; comments pass through */
116 out = n_pretty_xml("<div><br><!-- note --><span>x</span></div>");
117 expect_true("html returns output", out != NULL);
118 expect_contains("html br stays at depth", out, "\n <br>\n");
119 expect_contains("html comment kept", out, "\n <!-- note -->\n");
120 expect_contains("html span stays at depth", out, "\n <span>\n");
121 free_nstr(&out);
122
123 /* script content is raw text: the inner '<' is not a tag */
124 out = n_pretty_xml("<html><script>if(a<b){c();}</script></html>");
125 expect_true("html script returns output", out != NULL);
126 expect_contains("script content verbatim", out, "if(a<b){c();}");
127 expect_contains("script close tag kept", out, "</script>");
128 free_nstr(&out);
129
130 /* attribute values may contain '>' */
131 out = n_pretty_xml("<a title=\"1 > 0\">t</a>");
132 expect_true("xml quoted gt returns output", out != NULL);
133 expect_contains("xml quoted gt kept in tag", out, "<a title=\"1 > 0\">");
134 free_nstr(&out);
135
136 out = n_pretty_xml("plain text, no markup");
137 expect_true("xml non-markup returns NULL", out == NULL);
138 free_nstr(&out);
139 }
140
141 /* JavaScript */
142 {
143 N_STR* out = n_pretty_js("function f(a){if(a){return 1;}else{return 2;}}var x=f(1);");
144 expect_true("js valid returns output", out != NULL);
145 expect_contains("js opens a block", out, "{\n");
146 expect_contains("js indents body", out, "\n if(a){\n");
147 expect_contains("js indents nested body", out, "\n return 1;\n");
148 expect_contains("js statement gets its own line", out, "\nvar x=f(1);\n");
149 free_nstr(&out);
150
151 /* structural characters inside strings/regex must not break lines */
152 out = n_pretty_js("var s=\"x;y{z}\";var re=/a\\/b;{/g;var t='a;b';");
153 expect_true("js literals return output", out != NULL);
154 expect_contains("js double-quoted string intact", out, "\"x;y{z}\"");
155 expect_contains("js regex intact", out, "/a\\/b;{/g");
156 expect_contains("js single-quoted string intact", out, "'a;b'");
157 free_nstr(&out);
158
159 /* template literal spans lines and holds braces */
160 out = n_pretty_js("const q=`a{b}\n${x({})}`;done();");
161 expect_true("js template returns output", out != NULL);
162 expect_contains("js template intact", out, "`a{b}\n${x({})}`");
163 expect_contains("js statement after template", out, "done();");
164 free_nstr(&out);
165
166 /* a regex right after an expression keyword is a regex, not division */
167 out = n_pretty_js("function t(a){return /x;{/.test(a);}");
168 expect_true("js keyword regex returns output", out != NULL);
169 expect_contains("js regex after return intact", out, "return /x;{/.test(a);");
170 free_nstr(&out);
171
172 /* a '/' after an identifier or a closing paren is division */
173 out = n_pretty_js("var x=a/b;var y=f(1)/2;done();");
174 expect_true("js division returns output", out != NULL);
175 expect_contains("js division after identifier", out, "var x=a/b;\n");
176 expect_contains("js division after paren", out, "var y=f(1)/2;\n");
177 free_nstr(&out);
178
179 /* for(;;) semicolons at paren depth > 0 do not break the line */
180 out = n_pretty_js("for(i=0;i<3;i++){go(i);}");
181 expect_true("js for returns output", out != NULL);
182 expect_contains("js for header on one line", out, "for(i=0;i<3;i++){");
183 free_nstr(&out);
184
185 /* '} else {' style input: terminator glued to the closing brace */
186 out = n_pretty_js("a();};next();");
187 expect_true("js brace-semicolon returns output", out != NULL);
188 expect_contains("js terminator glued to brace", out, "\n};\n");
189 free_nstr(&out);
190 }
191
192 /* NULL / empty inputs */
193 expect_true("json NULL returns NULL", n_pretty_json(NULL) == NULL);
194 expect_true("xml NULL returns NULL", n_pretty_xml(NULL) == NULL);
195 expect_true("js NULL returns NULL", n_pretty_js(NULL) == NULL);
196 expect_true("xml empty returns NULL", n_pretty_xml("") == NULL);
197 expect_true("js empty returns NULL", n_pretty_js("") == NULL);
198
199 if (failures) {
200 n_log(LOG_ERR, "ex_pretty: %d failure(s)", failures);
201 return 1;
202 }
203 printf("ex_pretty: all tests passed\n");
204 return 0;
205}
static int failures
int main(void)
void process_args(int argc, char **argv)
Definition ex_common.c:48
static void expect_true(const char *label, int cond)
static void expect_contains(const char *label, const N_STR *out, const char *needle)
Definition ex_pretty.c:76
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
#define LOG_NULL
no log output
Definition n_log.h:46
#define LOG_INFO
informational
Definition n_log.h:82
N_STR * n_pretty_xml(const char *text)
Re-indent an XML or HTML document (one tag or text run per line).
Definition n_pretty.c:184
N_STR * n_pretty_js(const char *text)
Conservatively re-indent JavaScript (newlines at top-level braces and semicolons, two-space indent by...
Definition n_pretty.c:387
N_STR * n_pretty_json(const char *text)
Reformat a JSON document with cJSON (parse + print).
Definition n_pretty.c:89
char * data
the string
Definition n_str.h:63
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:203
A box including a string and his lenght.
Definition n_str.h:61
Common headers and low-level functions & define.
Generic log system.
Lexical pretty-printers for JSON, XML/HTML and JavaScript text.
N_STR and string function declaration.