Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_pretty.c

n_pretty regression: JSON, XML/HTML and JavaScript reformatting.

n_pretty regression: JSON, XML/HTML and JavaScript reformatting.

Author
Castagnier Mickael
Version
1.0
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nilorea/n_log.h"
#include "nilorea/n_str.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static int failures = 0;
/* Parse the -V LOG_LEVEL verbosity argument. */
static void process_args(int argc, char** argv) {
int opt = 0;
while ((opt = getopt(argc, argv, "hvV:")) != EOF) {
switch (opt) {
case 'V':
if (!strncmp("LOG_NULL", optarg, 8))
else if (!strncmp("LOG_NOTICE", optarg, 10))
else if (!strncmp("LOG_INFO", optarg, 8))
else if (!strncmp("LOG_ERR", optarg, 7))
else if (!strncmp("LOG_DEBUG", optarg, 9))
else {
fprintf(stderr, "Unknown log level %s\n", optarg);
exit(1);
}
break;
case 'v':
fprintf(stderr, "ex_pretty\n");
exit(1);
default:
fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
exit(1);
}
}
}
static void expect_true(const char* label, int cond) {
if (!cond) {
n_log(LOG_ERR, "%s: condition false", label);
}
}
static void expect_contains(const char* label, const N_STR* out, const char* needle) {
if (!out || !out->data || !strstr(out->data, needle)) {
n_log(LOG_ERR, "%s: output does not contain '%s' (got: %s)",
label, needle, (out && out->data) ? out->data : "NULL");
}
}
int main(int argc, char** argv) {
process_args(argc, argv);
/* JSON */
{
N_STR* out = n_pretty_json("{\"a\":1,\"b\":[true,null],\"c\":\"x\"}");
expect_true("json valid returns output", out != NULL);
expect_contains("json output is multi-line", out, "\n");
expect_contains("json key survives", out, "\"a\":");
free_nstr(&out);
out = n_pretty_json("this is not json");
expect_true("json garbage returns NULL", out == NULL);
free_nstr(&out);
out = n_pretty_json("{\"a\":");
expect_true("json truncated returns NULL", out == NULL);
free_nstr(&out);
}
/* XML / HTML */
{
N_STR* out = n_pretty_xml("<root><a x=\"1\"><b>hi</b></a></root>");
expect_true("xml valid returns output", out != NULL);
expect_contains("xml child is indented", out, "\n <a x=\"1\">\n");
expect_contains("xml grandchild is indented", out, "\n <b>\n");
expect_contains("xml text is indented", out, "\n hi\n");
expect_contains("xml close returns to depth", out, "\n</root>\n");
free_nstr(&out);
/* void element must not indent what follows; comments pass through */
out = n_pretty_xml("<div><br><!-- note --><span>x</span></div>");
expect_true("html returns output", out != NULL);
expect_contains("html br stays at depth", out, "\n <br>\n");
expect_contains("html comment kept", out, "\n <!-- note -->\n");
expect_contains("html span stays at depth", out, "\n <span>\n");
free_nstr(&out);
/* script content is raw text: the inner '<' is not a tag */
out = n_pretty_xml("<html><script>if(a<b){c();}</script></html>");
expect_true("html script returns output", out != NULL);
expect_contains("script content verbatim", out, "if(a<b){c();}");
expect_contains("script close tag kept", out, "</script>");
free_nstr(&out);
/* attribute values may contain '>' */
out = n_pretty_xml("<a title=\"1 > 0\">t</a>");
expect_true("xml quoted gt returns output", out != NULL);
expect_contains("xml quoted gt kept in tag", out, "<a title=\"1 > 0\">");
free_nstr(&out);
out = n_pretty_xml("plain text, no markup");
expect_true("xml non-markup returns NULL", out == NULL);
free_nstr(&out);
}
/* JavaScript */
{
N_STR* out = n_pretty_js("function f(a){if(a){return 1;}else{return 2;}}var x=f(1);");
expect_true("js valid returns output", out != NULL);
expect_contains("js opens a block", out, "{\n");
expect_contains("js indents body", out, "\n if(a){\n");
expect_contains("js indents nested body", out, "\n return 1;\n");
expect_contains("js statement gets its own line", out, "\nvar x=f(1);\n");
free_nstr(&out);
/* structural characters inside strings/regex must not break lines */
out = n_pretty_js("var s=\"x;y{z}\";var re=/a\\/b;{/g;var t='a;b';");
expect_true("js literals return output", out != NULL);
expect_contains("js double-quoted string intact", out, "\"x;y{z}\"");
expect_contains("js regex intact", out, "/a\\/b;{/g");
expect_contains("js single-quoted string intact", out, "'a;b'");
free_nstr(&out);
/* template literal spans lines and holds braces */
out = n_pretty_js("const q=`a{b}\n${x({})}`;done();");
expect_true("js template returns output", out != NULL);
expect_contains("js template intact", out, "`a{b}\n${x({})}`");
expect_contains("js statement after template", out, "done();");
free_nstr(&out);
/* a regex right after an expression keyword is a regex, not division */
out = n_pretty_js("function t(a){return /x;{/.test(a);}");
expect_true("js keyword regex returns output", out != NULL);
expect_contains("js regex after return intact", out, "return /x;{/.test(a);");
free_nstr(&out);
/* a '/' after an identifier or a closing paren is division */
out = n_pretty_js("var x=a/b;var y=f(1)/2;done();");
expect_true("js division returns output", out != NULL);
expect_contains("js division after identifier", out, "var x=a/b;\n");
expect_contains("js division after paren", out, "var y=f(1)/2;\n");
free_nstr(&out);
/* for(;;) semicolons at paren depth > 0 do not break the line */
out = n_pretty_js("for(i=0;i<3;i++){go(i);}");
expect_true("js for returns output", out != NULL);
expect_contains("js for header on one line", out, "for(i=0;i<3;i++){");
free_nstr(&out);
/* '} else {' style input: terminator glued to the closing brace */
out = n_pretty_js("a();};next();");
expect_true("js brace-semicolon returns output", out != NULL);
expect_contains("js terminator glued to brace", out, "\n};\n");
free_nstr(&out);
}
/* NULL / empty inputs */
expect_true("json NULL returns NULL", n_pretty_json(NULL) == NULL);
expect_true("xml NULL returns NULL", n_pretty_xml(NULL) == NULL);
expect_true("js NULL returns NULL", n_pretty_js(NULL) == NULL);
expect_true("xml empty returns NULL", n_pretty_xml("") == NULL);
expect_true("js empty returns NULL", n_pretty_js("") == NULL);
if (failures) {
n_log(LOG_ERR, "ex_pretty: %d failure(s)", failures);
return 1;
}
printf("ex_pretty: all tests passed\n");
return 0;
}
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.