diff options
Diffstat (limited to 'tests/custom/03_stdlib/28_printf')
-rw-r--r-- | tests/custom/03_stdlib/28_printf | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/tests/custom/03_stdlib/28_printf b/tests/custom/03_stdlib/28_printf new file mode 100644 index 0000000..a2a6d27 --- /dev/null +++ b/tests/custom/03_stdlib/28_printf @@ -0,0 +1,526 @@ +The `printf()` function formats given input value according to a format +string specified as first argument. The format string mimicks the syntax +and directives used by C printf(). + +Each directive (with the exception of %%) in the format string expects +a corresponding argument. If fewer arguments are passed to printf() than +required by the format string, missing values will be assumed to be `null` +and be interpreted accordingly. Excess arguments are ignored. + +Writes the output string formatted according to the format string with all +format directives interpolated by their respective values to the standard +output stream of the VM. + +Returns the number of bytes written to the output stream. + +Writes an empty string in case the format string argument is not a valid +string value. + +-- Testcase -- +{% + // String interpolation, corresponding value will be converted + // into string if needed. + printf("Hello %s!\n", "World"); + printf("Hello %s!\n", false); + printf("Hello %s!\n", 123); + printf("Hello %s!\n", null); + printf("Hello %s!\n"); + + // Signed integer interpolation, corresponding value will be + // converted into integer if needed. Also `d` and `i` are aliases. + printf("%d\n", 123); + printf("%i\n", 456.789); + printf("%d\n", true); + printf("%d\n", "0x42"); + printf("%d\n", "invalid"); + printf("%d\n", null); + printf("%d\n", 0xffffffffffffffff); + printf("%d\n"); + + // Unsigned integer interpolation in decimal notation, corresponding + // value will be converted into unsigned integer if needed. + printf("%u\n", 123); + printf("%u\n", -123); + printf("%u\n", 0xffffffffffffffff); + printf("%u\n", 456.789); + printf("%u\n", "invalid"); + printf("%u\n", null); + printf("%u\n"); + + // Unsigned integer interpolation in octal notation, corresponding + // value will be converted into unsigned integer if needed. + printf("%o\n", 123); + printf("%o\n", -123); + printf("%o\n", 0xffffffffffffffff); + printf("%o\n", 456.789); + printf("%o\n", "invalid"); + printf("%o\n", null); + printf("%o\n"); + + // Unsigned integer interpolation in lower case hexadecimal notation, + // corresponding value will be converted into unsigned integer if + // needed. + printf("%x\n", 123); + printf("%x\n", -123); + printf("%x\n", 0xffffffffffffffff); + printf("%x\n", 456.789); + printf("%x\n", "invalid"); + printf("%x\n", null); + printf("%x\n"); + + // Unsigned integer interpolation in upper case hexadecimal notation, + // corresponding value will be converted into unsigned integer if + // needed. + printf("%X\n", 123); + printf("%X\n", -123); + printf("%X\n", 0xffffffffffffffff); + printf("%X\n", 456.789); + printf("%X\n", "invalid"); + printf("%X\n", null); + printf("%X\n"); + + // Floating point value interpolation in exponential notation, + // corresponding value will be converted to double if needed. + printf("%e\n", 123); + printf("%e\n", -123); + printf("%e\n", 456.789); + printf("%e\n", -456.789); + printf("%e\n", "invalid"); + printf("%e\n", null); + printf("%e\n"); + + // Floating point value interpolation in exponential notation, + // using uppercase characters. Corresponding value will be converted + // to double if needed. + printf("%E\n", 123); + printf("%E\n", -123); + printf("%E\n", 456.789); + printf("%E\n", -456.789); + printf("%E\n", "invalid"); + printf("%E\n", null); + printf("%E\n"); + + // Floating point value interpolation in decimal point notation, + // corresponding value will be converted to double if needed. + printf("%f\n", 123); + printf("%f\n", -123); + printf("%f\n", 456.789); + printf("%f\n", -456.789); + printf("%f\n", "invalid"); + printf("%f\n", null); + printf("%f\n"); + + // Floating point value interpolation in decimal point notation, + // using uppercase characters. Corresponding value will be converted + // to double if needed. + printf("%F\n", 123); + printf("%F\n", -123); + printf("%F\n", 456.789); + printf("%F\n", -456.789); + printf("%F\n", "invalid"); + printf("%F\n", null); + printf("%F\n"); + + // Floating point value interpolation in either decimal point or + // exponential notation, depending on size of exponent. Corresponding + // value will be converted to double if needed. + printf("%g\n", 123.456); + printf("%g\n", 0.0000001); + printf("%g\n", "invalid"); + + // Floating point value interpolation in either decimal point or + // exponential notation, depending on size of exponent and using + // uppercase characters. Corresponding value will be converted to + // double if needed. + printf("%G\n", 123.456); + printf("%G\n", 0.0000001); + printf("%G\n", "invalid"); + + // Character interpolation. The corresponding value is casted as `char` + // and the resulting character is interpolated. + printf("%c\n", 65); + //printf("%c\n", -1); + //printf("%c\n", 456.789); + //printf("%c\n", "invalid"); + + // JSON interpolation. The corresponding value is JSON encoded and + // interpolated as string. + printf("%J\n", "Hello\n"); + printf("%J\n", 123); + printf("%J\n", [ 1, 2, 3 ]); + printf("%J\n", { some: "dictionary", an: [ "array", true, false ] }); + printf("%J\n", null); + printf("%J\n"); + + // Escaping `%`. The `%%` format string will produce a literal `%`. + // No corresponding argument is expected. + printf("%%\n"); +%} +-- End -- + +-- Expect stdout -- +Hello World! +Hello false! +Hello 123! +Hello (null)! +Hello (null)! +123 +456 +1 +66 +0 +0 +-1 +0 +123 +18446744073709551493 +18446744073709551615 +456 +0 +0 +0 +173 +1777777777777777777605 +1777777777777777777777 +710 +0 +0 +0 +7b +ffffffffffffff85 +ffffffffffffffff +1c8 +0 +0 +0 +7B +FFFFFFFFFFFFFF85 +FFFFFFFFFFFFFFFF +1C8 +0 +0 +0 +1.230000e+02 +-1.230000e+02 +4.567890e+02 +-4.567890e+02 +nan +0.000000e+00 +0.000000e+00 +1.230000E+02 +-1.230000E+02 +4.567890E+02 +-4.567890E+02 +NAN +0.000000E+00 +0.000000E+00 +123.000000 +-123.000000 +456.789000 +-456.789000 +nan +0.000000 +0.000000 +123.000000 +-123.000000 +456.789000 +-456.789000 +NAN +0.000000 +0.000000 +123.456 +1e-07 +nan +123.456 +1E-07 +NAN +A +"Hello\n" +123 +[ 1, 2, 3 ] +{ "some": "dictionary", "an": [ "array", true, false ] } +null +null +% +-- End -- + + +Field widths may be specified for format directives. + +-- Testcase -- +{% + // by default the output of a format directive is as long as the + // string representation of the corresponding value + printf("[%s]\n", "test"); + + // by specifying a field width, the output will be padded to the + // given length + printf("[%10s]\n", "test"); + + // the same applies to numbers + printf("[%10d]\n", 123); + printf("[%10f]\n", 1.0); + + // and to char formats + printf("[%10c]\n", 65); + + // field width is not applicable to `%` formats + printf("[%10%]\n"); +%} +-- End -- + +-- Expect stdout -- +[test] +[ test] +[ 123] +[ 1.000000] +[ A] +[%] +-- End -- + + +Precisions may be specified for format directives. + +-- Testcase -- +{% + // For `f`, `F`, `e` and `E`, the precision specifies the amount of + // digits after the comma + printf("[%.3f]\n", 1/3); + printf("[%.3F]\n", 1/3); + printf("[%.3e]\n", 1/3); + printf("[%.3E]\n", 1/3); + + // For `g` and `G` the precision specifies the number of significant + // digits to print before switching to exponential notation + printf("[%.3g]\n", 1000.1); + printf("[%.3G]\n", 1000.1); + + // For strings, the precision specifies the amount of characters to + // print at most + printf("[%.5s]\n", "test"); + printf("[%.3s]\n", "test"); + + // For JSON format, the precision specifies the amount of indentation + // to use. Omitting precision will not indent, specifying a precision + // of `0` uses tabs for indentation, any other precision uses this + // many spaces + printf("<%J>\n", [ 1, 2, 3, { true: false } ]), // no indent + printf("<%.J>\n", [ 1, 2, 3, { true: false } ]), // tab indent + printf("<%.0J>\n", [ 1, 2, 3, { true: false } ]), // tab indent + printf("<%.1J>\n", [ 1, 2, 3, { true: false } ]), // indent using one space + printf("<%.4J>\n", [ 1, 2, 3, { true: false } ]), // indent using four spaces + + // precision does not apply to char, integer or `%` formats + printf("[%.3d]\n", 1000); + printf("[%.3c]\n", 65); + printf("[%.3%]\n"); +%} +-- End -- + +-- Expect stdout -- +[0.000] +[0.000] +[0.000e+00] +[0.000E+00] +[1e+03] +[1E+03] +[test] +[tes] +<[ 1, 2, 3, { "true": false } ]> +<[ + 1, + 2, + 3, + { + "true": false + } +]> +<[ + 1, + 2, + 3, + { + "true": false + } +]> +<[ + 1, + 2, + 3, + { + "true": false + } +]> +<[ + 1, + 2, + 3, + { + "true": false + } +]> +[1000] +[A] +[%] +-- End -- + + +A number of flag characters are supported for format directives. + +-- Testcase -- +{% + // The recognized flag characters are `#`, `0`, `-`, `+` and ` ` (space) + printf("%#0+- s\n", "test"); + + // Repetitions of flag characters are accepted + printf("%###s\n", "test"); + printf("%000s\n", "test"); + printf("%++-s\n", "test"); + printf("%-- s\n", "test"); + printf("% s\n", "test"); + + // The `#` flag produces alternative forms of various conversions + printf("%o / %#o\n", 15, 15); + printf("%x / %#x\n", 16, 16); + printf("%X / %#X\n", 17, 17); + printf("%g / %#g\n", 1.0, 1.0); + + // The `0` flag indicates zero- instead of space-padding for various + // numeric conversions. + printf("[%5d / %05d]\n", -10, -10); + printf("[%5d / %05d]\n", 11, 11); + printf("[%5g / %05g]\n", -12.0, -12.0); + printf("[%5g / %05g]\n", 13.0, 13.0); + printf("[%5s / %05s]\n", "a", "a"); + + // The `-` flag indicates left, instead of right padding. It will + // override `0` and always pad with spaces + printf("[%-5d / %-05d]\n", -10, -10); + printf("[%-5d / %-05d]\n", 11, 11); + printf("[%-5g / %-05g]\n", -12.0, -12.0); + printf("[%-5g / %-05g]\n", 13.0, 13.0); + printf("[%-5s / %-05s]\n", "a", "a"); + + // The `+` flag indicates that a sign (`+` or `-`) should be placed + // before signed numeric values. It overrides ` ` (space). + printf("[%+5d / %+05d]\n", -10, -10); + printf("[%+5d / %+05d]\n", 11, 11); + printf("[%+5g / %+05g]\n", -12.0, -12.0); + printf("[%+5g / %+05g]\n", 13.0, 13.0); + printf("[%+5s / %+05s]\n", "a", "a"); + + // The ` ` (space) flag indicates that a blank should be placed + // before positive numbers (useful to ensure that negative and + // positive values in output are aligned) + printf("[%-5d / %- 5d]\n", -10, -10); + printf("[%-5d / %- 5d]\n", 11, 11); + printf("[%-5g / %- 5g]\n", -12.0, -12.0); + printf("[%-5g / %- 5g]\n", 13.0, 13.0); + printf("[%-5s / %- 5s]\n", "a", "a"); +%} +-- End -- + +-- Expect stdout -- +test +test +test +test +test +test +17 / 017 +10 / 0x10 +11 / 0X11 +1 / 1.00000 +[ -10 / -0010] +[ 11 / 00011] +[ -12 / -0012] +[ 13 / 00013] +[ a / a] +[-10 / -10 ] +[11 / 11 ] +[-12 / -12 ] +[13 / 13 ] +[a / a ] +[ -10 / -0010] +[ +11 / +0011] +[ -12 / -0012] +[ +13 / +0013] +[ a / a] +[-10 / -10 ] +[11 / 11 ] +[-12 / -12 ] +[13 / 13 ] +[a / a ] +-- End -- + + +Unrecognized format directives are copied to the output string as-is. + +-- Testcase -- +{% + // A truncated format directive is preserved + printf("test %\n", "test"); + printf("test %-010.3\n", "test"); + + // An unrecognized format directive is preserved + printf("test %y test\n", 123); + printf("test %~123s test\n", 123); +%} +-- End -- + +-- Expect stdout -- +test % +test %-010.3 +test %y test +test %~123s test +-- End -- + + +Missing values for format directives are treated as `null`. + +-- Testcase -- +{% + printf("%s\n"); + printf("%d\n"); + printf("%u\n"); + printf("%o\n"); + printf("%x\n"); + printf("%X\n"); + printf("%f\n"); + printf("%F\n"); + printf("%e\n"); + printf("%E\n"); + printf("%g\n"); + printf("%G\n"); + //printf("%c\n"); + printf("%J\n"); +%} +-- End -- + +-- Expect stdout -- +(null) +0 +0 +0 +0 +0 +0.000000 +0.000000 +0.000000e+00 +0.000000E+00 +0 +0 +null +-- End -- + + +Supplying a non-string format value will yield an empty string result. + +-- Testcase -- +{% + printf(true, 1, 2, 3); +%} +-- End -- + +-- Expect stdout -- +-- End -- |