├── .github └── workflows │ └── bats-multi-bash.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── bash-tpl └── test ├── block_indents.bats ├── delim-env.bats ├── delim-functions.bats ├── delim-regexes.bats ├── lib └── diff.bash ├── misc-functions.bats ├── statement_indents.bats ├── states.bats ├── template-regexes.bats ├── text_indents.bats ├── tpl.bats.bats ├── tpl.bats.sh ├── tpl.bats.tpl └── tpl ├── complex_text.sh ├── complex_text.tpl ├── complex_text.txt ├── formatted_text.sh ├── formatted_text.tpl ├── formatted_text.txt ├── hello_world.sh ├── hello_world.tpl ├── hello_world.txt ├── include_missing_err.sh ├── include_missing_err.stderr ├── include_missing_err.tpl ├── include_missing_err.txt ├── include_missing_ok.sh ├── include_missing_ok.stderr ├── include_missing_ok.tpl ├── include_missing_ok.txt ├── include_simple.inc ├── include_simple.sh ├── include_simple.tpl ├── include_simple.txt ├── include_undent.sh ├── include_undent.tpl ├── include_undent.txt ├── regression01.sh ├── regression01.tpl ├── regression01.txt ├── script_block.sh ├── script_block.tpl ├── script_block.txt ├── script_block_text.sh ├── script_block_text.tpl ├── script_block_text.txt ├── script_tag.sh ├── script_tag.tpl ├── script_tag.txt ├── script_tag_indent.sh ├── script_tag_indent.tpl ├── script_tag_indent.txt ├── text_with_dollar.sh ├── text_with_dollar.tpl ├── text_with_dollar.txt ├── text_with_escapes.sh ├── text_with_escapes.tpl ├── text_with_escapes.txt ├── text_with_quotes.sh ├── text_with_quotes.tpl ├── text_with_quotes.txt ├── text_with_tabs.sh ├── text_with_tabs.tpl ├── text_with_tabs.txt ├── tpl_comment.sh ├── tpl_comment.tpl ├── tpl_comment.txt ├── var_with_escapes.sh ├── var_with_escapes.tpl └── var_with_escapes.txt /.github/workflows/bats-multi-bash.yml: -------------------------------------------------------------------------------- 1 | name: BATS Tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | bats: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | bash: ["bash:3.2", "bash:4.4", "bash:5.0", "bash:5.1", "bash:5.2"] 17 | container: 18 | image: ${{ matrix.bash }} 19 | steps: 20 | - name: Install packages 21 | run: apk add diffutils 22 | 23 | - name: Setup BATS 24 | uses: mig4/setup-bats@v1.2.0 25 | with: 26 | bats-version: 1.7.0 27 | 28 | - name: Checkout code 29 | uses: actions/checkout@v2 30 | 31 | - name: Run bash-tpl tests 32 | run: bats test/ 33 | 34 | - name: Run template tests 35 | run: bats test/tpl 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # test tempates in root folder 2 | # 3 | /*.tpl 4 | /*.sh 5 | /*.bash 6 | 7 | # auto-generated tpl.bats 8 | # 9 | /test/tpl/tpl.bats 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | # Standard hooks 3 | # 4 | - repo: git://github.com/pre-commit/pre-commit-hooks 5 | rev: v2.3.0 6 | hooks: 7 | - id: check-merge-conflict 8 | # - id: check-yaml 9 | - id: end-of-file-fixer 10 | - id: trailing-whitespace 11 | # Bash helper hooks (local) 12 | # 13 | - repo: local 14 | hooks: 15 | # shellcheck (aliased to shck) 16 | # 17 | - id: shellcheck 18 | name: Run static analysis on bash-tpl (shellcheck) 19 | entry: shellcheck 20 | language: system 21 | files: "^bash-tpl$" 22 | types: [file] 23 | alias: shck 24 | # shfmt 25 | # 26 | - id: shfmt 27 | name: Run lint check on bash-tpl (shfmt -d) 28 | entry: shfmt 29 | language: system 30 | files: "^bash-tpl$" 31 | types: [file] 32 | args: [ '-i', '0', '-ci', '-sr', '-d' ] 33 | # shfmt -w (must manually invoke) 34 | # 35 | - id: shfmtw 36 | name: Auto-fix lint errors on bash-tpl (shfmt -w) 37 | entry: shfmt 38 | language: system 39 | stages: [manual] 40 | files: "^bash-tpl$" 41 | types: [file] 42 | args: [ '-i', '0', '-ci', '-sr', '-kp', '-w' ] 43 | # bats standard test suite 44 | # 45 | - id: bats 46 | name: Run standard test suite (bats) 47 | entry: bats 48 | language: system 49 | stages: [commit] 50 | alias: test 51 | pass_filenames: false 52 | args: [ test ] 53 | # bats tpl test suite 54 | # 55 | - id: bats-tpl 56 | name: Run tpl test suite (bats) 57 | entry: bats 58 | language: system 59 | stages: [commit] 60 | alias: test-tpl 61 | pass_filenames: false 62 | args: [ test/tpl ] 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 TekWizely & co-authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bash-TPL [![MIT license](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/tekwizely/pre-commit-golang/blob/master/LICENSE) 2 | 3 | A Smart, lightweight shell script templating engine, written in Bash. 4 | 5 | Bash-TPL lets you mark up textual files (config files, yaml, xml, scripts, html, etc.) with shell commands and variable replacements, while minimally impacting your original file layout. 6 | 7 | Templates are compiled into shell scripts that you can invoke (along with variables, arguments, etc.) to generate complete and well-formatted output text files. 8 | 9 | #### Features 10 | 11 | ##### Lightweight 12 | 13 | Bash-TPL is presented as a single-file Bash script, making it both easy to bring along with your projects, and even easier to use, since there is no need to compile any source code. 14 | 15 | See [Adding `bash-tpl` into your project](#adding-bash-tpl-into-your-project) for more information. 16 | 17 | ##### Smart Indentation Correction 18 | 19 | Creating readable, maintainable templates often requires adding extra whitespace (i.e. indenting lines within a `for` loop) in order to help distinguish your template tags from your textual content. 20 | 21 | Bash-TPL detects ands removes these extra indentations, resulting in generated text files that look as good as if they were written by hand ! 22 | 23 | *NOTE: Consistent Formatting* 24 | 25 | The key to success with Bash-TPL's indentation fix-up logic is _Consistent Formatting_ - using consistent indentation throughout your templates will yield best results. 26 | 27 | ##### Generates Reusable Shell Scripts 28 | 29 | The output of Bash-TPL is a reusable shell script that is then used to generate your final text document(s). 30 | 31 | If desired, you could just bring/ship the intermediate script, with no further need for Bash-TPL until you need to make changes to your original template. 32 | 33 | ##### Shell Agnostic 34 | 35 | The shell scripts that Bash-TPL generates are not intended to be Bash-specific. 36 | 37 | Bash-TPL attempts to generate posix printf-compatible statements, utilizing `%s` and `%b`. 38 | 39 | Any shell who's printf matches output below should be compatible: 40 | 41 | ```sh 42 | $ VARIABLE=Variable 43 | $ printf "%b%s%b%s%b\n" 'Text:\t\0047' "$VARIABLE" '\0047 "' "$(echo $VARIABLE)" '" $(\\n)' 44 | ``` 45 | ```text 46 | Text: 'Variable' "Variable" $(\n) 47 | ``` 48 | 49 | ##### Custom Formatting 50 | 51 | Although template tags are formatted with `%s` by default, you can customize their format using standard _printf_ format specifiers. 52 | 53 | See [Formatting Text Tags](#formatting-text-tags) for more information. 54 | 55 | ##### Supports Includes 56 | 57 | Templates can include other templates, making it easy to organize your templates as smaller, reusable components. 58 | 59 | *NOTE:* Bash-TPL's smart indentation tracking & correction even works across included templates ! 60 | 61 | The indentation of the `include` statement dictates the base indentation of the included file. 62 | 63 | See [INCLUDE directive](#include) for more information. 64 | 65 | ##### Configurable Delimiters 66 | 67 | Bash-TPL's default delimiters _should_ accommodate most text file formats without conflict. 68 | 69 | But if you do run into conflicts, or if you just prefer a different style, the delimiters are fully configurable. 70 | 71 | You can even modify delimiters mid-template ! 72 | 73 | See [Customizing Delimiters](#customizing-delimiters) for more information. 74 | 75 | *NOTE: Including Templates With Differing Delimiters* 76 | 77 | You can easily include templates that have differing delimiters. 78 | 79 | If the included template doesn't declare its delimiters explicitly (i.e. maybe it relies on the defaults), you can specify the delimiters as part of the include statement. 80 | 81 | See [INCLUDE directive](#include) for more information. 82 | 83 | ##### Extensive Test Suite 84 | 85 | Bash-TPL has an extensive test suite built wth [BATS](https://github.com/bats-core/bats-core) 86 | 87 | *Older Bash Versions* 88 | 89 | The test suite has been tested against Bash versions `3.2`, `4.4`, `5.0`, and `5.1` 90 | 91 | #### TOC 92 | - [Template Tags](#template-tags) 93 | - [Text Tags](#text-tags) 94 | - [Formatting Text Tags](#formatting-text-tags) 95 | - [Statement Lines](#statement-lines) 96 | - [Statement Blocks](#statement-blocks) 97 | - [Template Comments](#template-comments) 98 | - [Directives](#directives) 99 | - [INCLUDE](#include) 100 | - [DELIMS](#delims) 101 | - [RESET-DELIMS](#reset-delims) 102 | - [Customizing Delimiters](#customizing-delimiters) 103 | - [Resetting Delimiters](#resetting-delimiters) 104 | - [Installing](#installing) 105 | - [Contributing](#contributing) 106 | - [Contact](#contact) 107 | - [License](#license) 108 | - [Adding `bash-tpl` into your project](#adding-bash-tpl-into-your-project) 109 | 110 | -------- 111 | ## Using 112 | 113 | bash-tpl takes a single template file as input and generates a shell script as output. 114 | 115 | _basic usage_ 116 | 117 | ``` 118 | $ bash-tpl my_template.tpl > my_script.sh 119 | ``` 120 | 121 | #### Reading From STDIN 122 | 123 | In addition to files, bash-tpl can also read directly from `stdin`. 124 | 125 | To read from `stdin`, use a single `-` as the input filename: 126 | 127 | _stdin example_ 128 | ``` 129 | $ bash-tpl - > hello.sh 130 | Hello, world 131 | ^D 132 | ``` 133 | 134 | ##### Other stdin sources 135 | 136 | You can also use other common `stdin` sources: 137 | 138 | _pipe example_ 139 | ``` 140 | $ echo "Hello, world" | bash-tpl - > hello.sh 141 | ``` 142 | 143 | _herestring (`<<<`) example_ 144 | ``` 145 | $ bash-tpl - <<< "Hello, world" > hello.sh 146 | ``` 147 | 148 | _heredoc (`<<`) example_ 149 | ``` 150 | $ bash-tpl - > hello.sh < 196 | ``` 197 | 198 | #### Processing The Template 199 | 200 | We can process the template and review the generated script: 201 | 202 | _process the template_ 203 | ``` 204 | $ bash-tpl hello.tpl 205 | 206 | printf "%b%s\n" 'Hello ' "$NAME" 207 | ``` 208 | 209 | #### Usage Example 210 | 211 | Here's a quick example invoking the template-generated script along with some user data: 212 | 213 | _usage example_ 214 | ``` 215 | $ NAME=TekWizely source <( bash-tpl hello.tpl ) 216 | 217 | Hello TekWizely 218 | ``` 219 | 220 | ##### Default Delimiters 221 | 222 | The default delimiters for standard tags are `<%` & `%>` 223 | 224 | See the [Customizing Delimiters](#customizing-delimiters) section to learn about the many ways you can customize delimiters to your liking. 225 | 226 | ##### Trimming 227 | 228 | **NOTE:** For standard tags, The value within the delimiters is 'trimmed' before being processed, ie: `'<% $NAME %>'` is equivalent to `'<%$NAME%>'`. 229 | 230 | This is to encourage you to use liberal amounts of whitespace, keeping your templates easy to read and maintain. 231 | 232 | #### Quote Tag 233 | 234 | Quote tags are similar to standard tags, with the exception that *no trimming* is performed, and leading/trailing whitespace is preserved, ie: 235 | 236 | ``` 237 | Hello <%" $NAME "%> 238 | ``` 239 | 240 | Is equivalent to : 241 | 242 | ``` 243 | printf "%b%s\n" 'Hello ' " $NAME " # Whitespace around $NAME is preserved 244 | ``` 245 | 246 | ##### Default Delimiters 247 | 248 | The default delimiters for Quote Tags are `<%"` & `"%>` 249 | 250 | More specifically, the delimiters are : Currently-configured Standard Tag delimiters with leading & trailing quotes (`"`) 251 | 252 | NOTE: No whitespace is allowed between the standard tag and the quote character (i.e. `<% "` would **not** be treated as a quote tag). 253 | 254 | ##### Example 255 | 256 | _hello.tpl_ 257 | ``` 258 | Hello '<%" <% $NAME %> "%>' 259 | ``` 260 | 261 | ``` 262 | $ NAME=TekWizely source <( bash-tpl hello.tpl ) 263 | 264 | Hello ' <% TekWizely %> ' 265 | ``` 266 | 267 | #### Statement Tag 268 | 269 | Statement tags allow you to inline script statements, printing the output of the statement: 270 | 271 | ``` 272 | Hello <%% echo $NAME %> 273 | ``` 274 | 275 | Is equivalent to : 276 | 277 | ``` 278 | printf "%b%s\n" 'Hello ' "$(echo $NAME)" # Trivial example to demonstrate the conversion 279 | ``` 280 | 281 | ##### Better Example 282 | 283 | A *slightly* more useful example of a statement tag might be: 284 | 285 | _hello.tpl_ 286 | ``` 287 | Hello <%% echo $NAME | tr '[:lower:]' '[:upper:]' %> 288 | ``` 289 | 290 | ``` 291 | $ NAME=TekWizely source <( bash-tpl hello.tpl ) 292 | 293 | Hello TEKWIZELY 294 | ``` 295 | 296 | ##### Default Delimiters 297 | 298 | The default delimiters for Statement Tags are `<%%` & `%>` 299 | 300 | More specifically, the delimiters are : Currently-configured Standard Tag delimiters with the open delimiter followed by the Statement Tag delimiter. 301 | 302 | **NOTES:** 303 | * The statement Tag delimiter (ie the 2nd `%`) can be configured separate from the Standard Tag delimiters. See [Customizing Delimiters](#customizing-delimiters) for details. 304 | * No whitespace is allowed between the Standard Tag and the Statement Tag delimiter (i.e. `<% %` would **not** be treated as a Statement Tag). 305 | * The Statement Tag delimiter is *not* part of the close tag (`%>`), **just** the open tag (`<%%`) 306 | 307 | ##### Trimming 308 | 309 | **NOTE:** As with Standard Tags, the value within the statement Tag is 'trimmed' before being processed, ie: `'<%% echo $NAME %>'` is equivalent to `'<%%echo $NAME%>'`. 310 | 311 | ### Formatting Text Tags 312 | 313 | By default, all Text Tags are rendered with the _printf_ `%s` format specifier. 314 | 315 | You can use a custom format specifier in your tags: 316 | 317 | _integer_format.tpl_ 318 | ``` 319 | % myint=123 320 | <%|%d|${myint}%> 321 | ``` 322 | 323 | _process the template_ 324 | ``` 325 | $ bash-tpl integer_format.tpl 326 | 327 | myint=123 328 | printf "%d\n" "${myint}" 329 | ``` 330 | 331 | #### Whitespace Ignored 332 | 333 | You can add extra whitespace to make your tags easier to read: 334 | 335 | _integer_format_spaced.tpl_ 336 | ``` 337 | % myint=123 338 | <% | %d | ${myint} %> 339 | ``` 340 | 341 | Processing the template generates the same output as the above (no-whitespace) example: 342 | 343 | _process the template_ 344 | ``` 345 | $ bash-tpl integer_format_spaced.tpl 346 | 347 | myint=123 348 | printf "%d\n" "${myint}" 349 | ``` 350 | 351 | #### Variable as Format Specifier 352 | 353 | Other than trimming whitespace from the beginning/end of the format specifier, the value is passed as-is to the final output. 354 | 355 | This allows you to do things such as use a variable as the format specifier: 356 | 357 | _integer_format_var.tpl_ 358 | ``` 359 | % myint=123 360 | % myfmt='%05d' 361 | <% | ${myfmt} | ${myint} %> 362 | ``` 363 | 364 | _process the template_ 365 | ``` 366 | $ bash-tpl integer_format_var.tpl 367 | 368 | myint=123 369 | myfmt='%05d' 370 | printf "${myfmt}\n" "${myint}" 371 | ``` 372 | 373 | Invoking the template shows that the output is formatted according to the value of `${myfmt}`: 374 | 375 | _invoke template script_ 376 | ``` 377 | $ source <( bash-tpl integer_format_var.tpl ) 378 | 379 | 00123 380 | ``` 381 | 382 | #### Default Delimiters 383 | 384 | The default delimiters for the format specifier are `|` & `|` 385 | 386 | You can customize the delimiters: 387 | 388 | _customized_format_delimiters.tpl_ 389 | ``` 390 | .DELIMS tag-fmt="[ ]" 391 | % myint=123 392 | <%[%d] $myint %> 393 | ``` 394 | 395 | _process the template_ 396 | ``` 397 | $ bash-tpl customized_format_delimiters.tpl 398 | 399 | myint=123 400 | printf "%d\n" "$myint" 401 | ``` 402 | 403 | See the [Customizing Delimiters](#customizing-delimiters) section to learn about the many ways you can customize delimiters to your liking. 404 | 405 | ------------------- 406 | ### Statement Lines 407 | 408 | Statement lines allow you to easily insert a single line of script into your template: 409 | 410 | _test.tpl_ 411 | ``` 412 | % [ -z "$1" ] && echo "Error: Missing argument" >&2 && return 413 | Hello <% $1 %> 414 | ``` 415 | 416 | _test with no arguments_ 417 | ``` 418 | $ source <( bash-tpl test.tpl ) 419 | 420 | Error: Missing argument 421 | ``` 422 | 423 | _test with argument_ 424 | ``` 425 | $ source <( bash-tpl test.tpl ) TekWizely 426 | 427 | Hello TekWizely 428 | ``` 429 | 430 | -------------------- 431 | ### Statement Blocks 432 | 433 | Statement blocks allow you to add a full script block into your template: 434 | 435 | ``` 436 | % 437 | if [ -z "${1}" ]; then 438 | echo "Error: Missing argument" >&2 439 | return 440 | fi 441 | % 442 | Hello <% $1 %> 443 | ``` 444 | 445 | **NOTE:** Statement Block delimiters must be on their own line with no other non-whitespace characters. 446 | 447 | _test with no arguments_ 448 | ``` 449 | $ source <( bash-tpl test.tpl ) 450 | 451 | Error: Missing argument 452 | ``` 453 | 454 | _test with argument_ 455 | ``` 456 | $ source <( bash-tpl test.tpl ) TekWizely 457 | 458 | Hello TekWizely 459 | ``` 460 | 461 | ##### Default Delimiter 462 | 463 | The default start & stop delimiter for Statement Blocks is `%` 464 | 465 | More specifically, the default is : Currently-configured Statement Line delimiter. 466 | 467 | #### Printing Text Within a Statement Block 468 | 469 | Sometimes parts (or all) of your template may consist of complex code that just needs to print a small amount of text. 470 | 471 | You could close and re-open your statement blocks, but that might feel verbose depending on the situation: 472 | 473 | _verbose.tpl_ 474 | ``` 475 | % 476 | # ... 477 | if (condition); then 478 | % 479 | condition text ... 480 | % 481 | else 482 | % 483 | else text ... 484 | % 485 | fi 486 | # ... 487 | % 488 | ``` 489 | 490 | Bash-tpl allows you to print single lines of text within your statement blocks: 491 | 492 | _inline.tpl_ 493 | ``` 494 | % 495 | # ... 496 | if (condition); then 497 | % condition text ... 498 | else 499 | % else text ... 500 | fi 501 | # ... 502 | % 503 | ``` 504 | 505 | **NOTES:** 506 | * The indentation of the printed text lines will always match that of the statement block start tag 507 | * This is to encourage you to format your text lines within the context of your script 508 | * All whitespace _after_ the text line tag (`'% `') will be printed as-as 509 | 510 | ##### Similar Script Output 511 | 512 | The two techniques generate nearly-identical scripts, but the inline script is slightly easier to read: 513 | 514 | _verbose.sh_ 515 | ```bash 516 | # ... 517 | if (condition); then 518 | printf "%b\n" 'condition text ...' 519 | else 520 | printf "%b\n" 'else text ...' 521 | fi 522 | # ... 523 | ``` 524 | 525 | _inline.sh_ 526 | ```bash 527 | # ... 528 | if (condition); then 529 | printf "%b\n" 'condition text ...' 530 | else 531 | printf "%b\n" 'else text ...' 532 | fi 533 | # ... 534 | ``` 535 | 536 | ##### Default Delimiter 537 | 538 | The default delimiter for a Statement Block Text Line is `'% '` (note the trailing space `' '`) 539 | 540 | More specifically, the default is : Currently-configured Statement Line delimiter, followed by a space (`' '`) 541 | 542 | --------------------- 543 | ### Template Comments 544 | 545 | _test.tpl_ 546 | ``` 547 | %# This comment will be removed from the template script 548 | % # This comment will remain as part of the template script 549 | Hello world 550 | ``` 551 | 552 | _view raw template script_ 553 | ``` 554 | $ bash-tpl test.tpl 555 | 556 | # This comment will remain as part of the template script 557 | printf "%b\n" 'Hello world' 558 | ``` 559 | 560 | _invoke template script_ 561 | ``` 562 | $ source <( bash-tpl test.tpl ) 563 | 564 | Hello world 565 | ``` 566 | 567 | -------------- 568 | ### Directives 569 | 570 | #### INCLUDE 571 | 572 | _test.tpl_ 573 | ``` 574 | ARGS: 575 | %# Due to smart indentation tracking, 576 | %# indentations within the while statement are removed. 577 | % while (( "$#" )); do 578 | %# Indentation is even tracked across includes 579 | .INCLUDE include.tpl 580 | % shift 581 | % done 582 | ``` 583 | 584 | _include.tpl_ 585 | ``` 586 | - <% $1 %> 587 | ``` 588 | 589 | ``` 590 | $ source <( bash-tpl test.tpl ) a b c d 591 | 592 | ARGS: 593 | - a 594 | - b 595 | - c 596 | - d 597 | ``` 598 | 599 | **Support for potentially-missing files** 600 | 601 | You can safely attempt to include a potentially-missing file using `.INCLUDE?` 602 | 603 | _no errors if include file is missing_ 604 | ``` 605 | .INCLUDE? optional-file.tpl 606 | ``` 607 | 608 | **NOTES:** 609 | * The current delimiter configuration is passed to the included template 610 | * You can pass command-line options (i.e `--tag-delims`, `--reset-delims`, etc) 611 | 612 | #### DELIMS 613 | 614 | Configure one or more template delimiters from *within* your template. 615 | 616 | _test.tpl_ 617 | ``` 618 | %# We change the stmt block and tag delims 619 | %# NOTE: Both the '=' and double-quotes (") are required 620 | .DELIMS stmt-block="<% %>" tag="{{ }}" 621 | <% 622 | if [ -z "${1}" ]; then 623 | echo "Error: Missing argument" >&2 624 | return 625 | fi 626 | %> 627 | Hello {{ $1 }} 628 | ``` 629 | 630 | ``` 631 | $ source <( bash-tpl test.tpl ) TekWizely 632 | 633 | Hello TekWizely 634 | ``` 635 | 636 | **NOTES:** 637 | * Both the `=` and Double-Quotes (`"`) shown in the example script are **required** 638 | * The changes take effect immediately (i.e. the very next line) 639 | * The changes are passed along to any included templates 640 | 641 | The DELIMS directive accepts the following parameters: 642 | 643 | | PARAM | FORMAT | NOTE | 644 | |----------------------|------------|---------------------------------------------------------------| 645 | | TAG | `".. .."` | 2 two-char sequences, separated by a **single** space | 646 | | TAG-STMT | `"."` | 1 single character | 647 | | TAG-FMT | `". ."` | 2 single characters, separated by a **single** space | 648 | | STMT | `".+"` | 1 or more characters | 649 | | STMT-BLOCK | `".+ .+"` | 2 one-or-more char sequences, separated by a **single** space | 650 | | TXT | TEXT | `".+[ ]?"` | 1 or more characters, with an optional trailing space | 651 | | DIR | DIRECTIVE | `".+"` | 1 or more characters | 652 | | CMT | COMMENT | `".+"` | 1 or more characters | 653 | 654 | 655 | #### RESET-DELIMS 656 | 657 | Reset **all** delimiters to their default values from *within* you template. 658 | 659 | _test.tpl_ 660 | ``` 661 | % echo "default statement delim" 662 | .DELIMS stmt="$>" 663 | $> echo "modified statement delim" 664 | .RESET-DELIMS 665 | % echo "back to default statement delim" 666 | ``` 667 | 668 | ``` 669 | $ source <( bash-tpl test.tpl ) 670 | 671 | default statement delim 672 | modified statement delim 673 | back to default statement delim 674 | ``` 675 | 676 | -------------------------- 677 | ### Customizing Delimiters 678 | 679 | There are several ways to customize delimiters for your templates. 680 | 681 | #### Environment Variables 682 | 683 | You can change the default delimiters globally via the following environment variables: 684 | 685 | | VARIABLE | FORMAT | NOTE | 686 | |----------------------------|------------|---------------------------------------------------------------| 687 | | BASH_TPL_TAG_DELIMS | `".. .."` | 2 two-char sequences, separated by a **single** space | 688 | | BASH_TPL_TAG_STMT_DELIM | `"."` | 1 single character | 689 | | BASH_TPL_TAG_FMT_DELIMS | `". ."` | 2 single characters, separated by a **single** space | 690 | | BASH_TPL_STMT_DELIM | `".+"` | 1 or more characters | 691 | | BASH_TPL_STMT_BLOCK_DELIMS | `".+ .+"` | 1 one-or-more char sequences, separated by a **single** space | 692 | | BASH_TPL_TEXT_DELIM | `".+[ ]?"` | 1 or more characters, with an optional trailing space | 693 | | BASH_TPL_DIR_DELIM | `".+"` | 1 or more characters | 694 | | BASH_TPL_CMT_DELIM | `".+"` | 1 or more characters | 695 | 696 | ##### quick example 697 | 698 | _test.tpl_ 699 | ``` 700 | %# customize standard tag delimiter 701 | Hello, {{ $1 }} 702 | ``` 703 | 704 | ``` 705 | $ BASH_TPL_TAG_DELIMS="{{ }}" bash-tpl test.tpl > test.sh 706 | $ . test.sh TekWizely 707 | 708 | Hello, TekWizely 709 | ``` 710 | 711 | #### Command Line Options 712 | 713 | The following command line options are available for customizing delimiters: 714 | 715 | | OPTION | FORMAT | NOTE | 716 | |--------------------------------------|------------|---------------------------------------------------------------| 717 | | --tag-delims | `".. .."` | 2 two-char sequences, separated by a **single** space | 718 | | --tag-stmt-delim | `"."` | 1 single character | 719 | | --tag-fmt-delims | `". ."` | 2 single characters, separated by a **single** space | 720 | | --stmt-delim | `".+"` | 1 or more characters | 721 | | --stmt-block-delims | `".+ .+"` | 2 one-or-more char sequences, separated by a **single** space | 722 | | --txt-delim | --text-delim | `".+[ ]?"` | 1 or more characters, with an optional trailing space | 723 | | --dir-delim | --directive-delim | `".+"` | 1 or more characters | 724 | | --cmt-delim | --comment-delim | `".+"` | 1 or more characters | 725 | 726 | **NOTE:** Command-line options override environment variables. 727 | 728 | ##### quick example 729 | 730 | _test.tpl_ 731 | ``` 732 | %# customize standard tag delimiter 733 | Hello, {{ $1 }} 734 | ``` 735 | 736 | ``` 737 | $ bash-tpl --tag-delims "{{ }}" test.tpl > test.sh 738 | $ . test.sh TekWizely 739 | 740 | Hello, TekWizely 741 | ``` 742 | 743 | #### DELIMS Directive 744 | 745 | You can use the [DELIMS Directive](#delims) to configure delimiters from *within* your template. 746 | 747 | **NOTE:** DELIMS options override both environment variables and command-line options. 748 | 749 | ### Resetting Delimiters 750 | 751 | There are a couple of ways to reset the delimiters back to their default values. 752 | 753 | #### Command-Line Option 754 | 755 | You can use the `--reset-delims` option to reset the delimiters to defaults: 756 | 757 | ``` 758 | $ bash-tpl --reset-delims test.tpl 759 | ``` 760 | 761 | **NOTES:** 762 | * Overrides environment variables 763 | * Overrides any commend-line options that appear *before* the `--reset-delims` option 764 | * Does **not** override any command-line options that appear *after* the `--reset-delims` option 765 | * Can be passed as an option in an [INCLUDE](#include) directive, ie: 766 | ``` 767 | .INCLUDE my_include.tpl --reset-delims 768 | ``` 769 | 770 | #### RESET-DELIMS Directive 771 | 772 | You can use the [RESET-DELIMS Directive](#reset-delims) to reset delimiters from *within* your template. 773 | 774 | ------------- 775 | ## Installing 776 | 777 | ### Releases 778 | 779 | See the [Releases](https://github.com/TekWizely/bash-tpl/releases) page for downloadable archives of versioned releases. 780 | 781 | #### Brew Core 782 | TBD 783 | 784 | #### Brew Tap 785 | 786 | In addition to working on brew core support, I have also created a tap to ensure the latest version is always available: 787 | 788 | * https://github.com/TekWizely/homebrew-tap 789 | 790 | _install bash-tpl directly from tap_ 791 | ``` 792 | $ brew install tekwizely/tap/bash-tpl 793 | ``` 794 | 795 | _install tap to track updates_ 796 | ``` 797 | $ brew tap tekwizely/tap 798 | 799 | $ brew install bash-tpl 800 | ``` 801 | ## Similar Tools 802 | 803 | Here's a list of some similar tools I discovered before deciding to create bash-tpl : 804 | * [mo - mustache templates in bash](https://github.com/tests-always-included/mo) 805 | * [esh - embedded shell (written in sh)](https://github.com/jirutka/esh) 806 | * [envsubst (part of gnu gettext)](https://www.gnu.org/software/gettext/manual/html_node/envsubst-Invocation.html) 807 | * [shtpl (written in bash)](https://github.com/mlorenzo-stratio/shtpl) 808 | * [shtpl (written in vala)](https://github.com/dontsueme/shtpl) 809 | * [cookie (written in bash)](https://github.com/bbugyi200/cookie) 810 | * [bash-templater](https://github.com/vicentebolea/bash-templater) 811 | * [renderest (written in bash)](https://github.com/relaxdiego/renderest) 812 | * [rc template language](https://werc.cat-v.org/docs/rc-template-lang) 813 | * [pp shell-based pre-processor](https://adi.onl/pp.html) 814 | 815 | --------------- 816 | ## Contributing 817 | 818 | To contribute to Bash-TPL, follow these steps: 819 | 820 | 1. Fork this repository. 821 | 2. Create a branch: `git checkout -b `. 822 | 3. Make your changes and commit them: `git commit -m ''` 823 | 4. Push to the original branch: `git push origin /` 824 | 5. Create the pull request. 825 | 826 | Alternatively see the GitHub documentation on [creating a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request). 827 | 828 | ---------- 829 | ## Contact 830 | 831 | If you want to contact me you can reach me at TekWizely@gmail.com. 832 | 833 | ---------- 834 | ## License 835 | 836 | The `tekwizely/bash-tpl` project is released under the [MIT](https://opensource.org/licenses/MIT) License. See `LICENSE` file. 837 | 838 | ##### Adding `bash-tpl` into your project 839 | 840 | The `bash-tpl` script has an embedded MIT [SPDX](https://spdx.org/licenses/MIT.html) header, as well as a license header, and should be safe for you to extract and add to your own projects for easy template generation. 841 | -------------------------------------------------------------------------------- /bash-tpl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ####################################################################### 3 | # SPDX-License-Identifier: MIT 4 | # Copyright (c) 2021 TekWizely & co-authors 5 | # 6 | # Use of this source code is governed by the MIT license. 7 | # See the accompanying LICENSE file, if present, or visit: 8 | # https://opensource.org/licenses/MIT 9 | ####################################################################### 10 | VERSION="v0.9.0" 11 | ####################################################################### 12 | # Bash-TPL: A Smart, Lightweight shell script templating engine 13 | # 14 | # Lets you mark up textual files with shell commands and variable 15 | # replacements, while minimally impacting your original file layout. 16 | # 17 | # Templates are compiled into shell scripts that you can invoke 18 | # (along with variables, arguments, etc.) to generate complete and 19 | # well-formatted output text files. 20 | # 21 | # Smart 22 | # 23 | # Encourages you to use extra indentation to write clean, well- 24 | # formatted templates, and smartly removes the indentations from the 25 | # generated template scripts. 26 | # 27 | # This results in both templates that are easily readable and 28 | # maintainable, and generated text files that look as good as if they 29 | # were written by hand. 30 | # 31 | # NOTE: Consistent Formatting 32 | # 33 | # The key to success with Bash-TPL indentation fix-up logic is 34 | # Consistent Formatting; using consistent indentation throughout your 35 | # template will yield best results. 36 | # 37 | # Learn More: 38 | # https://github.com/TekWizely/bash-tpl 39 | ####################################################################### 40 | 41 | function usage() { 42 | cat << USAGE 43 | Bash-TPL is a smart, lightweight shell script templating engine 44 | 45 | usage: bash-tpl [flags] [--] file 46 | bash-tpl [flags] - 47 | cat file | bash-tpl [flags] 48 | 49 | options: 50 | -h, --help 51 | show help screen 52 | --version 53 | show version 54 | -o, --output-file 55 | write to specified file (default: stdout) 56 | -- treat remaining options as positional arguments 57 | - read from stdin 58 | 59 | customize delimiters: 60 | --tag-delims 'xx xx' 61 | set tag delimiters (default: '<% %>') 62 | --tag-stmt-delim 'x' 63 | set tag statement delimiter (default: '%') 64 | --tag-fmt-delims 'x x' 65 | set tag format-specifier delimiters (default: '| |') 66 | --stmt-delim 'x+' 67 | set statement delimiter (default: '%') 68 | --stmt-block-delims 'x+ x+' 69 | set statement block delimiters 70 | defaults to statement delimiter if not explicitly set 71 | --txt-delim 72 | --text-delim 'x+[ ]?' (single trailing space allowed) 73 | set text delimiter (default: '% ') 74 | --dir-delim 75 | --directive-delim 'x+' 76 | set directive delimiter (default: '.') 77 | --cmt-delim 78 | --comment-delim 'x+' 79 | set template comment delimiter 80 | defaults to directive delimiter + '#' if not explicitly set 81 | --reset-delims 82 | reset all delimiters to defaults 83 | delim options provided after this option are honored 84 | 85 | supported environment variables: 86 | BASH_TPL_TAG_DELIMS 87 | BASH_TPL_TAG_STMT_DELIM 88 | BASH_TPL_TAG_FMT_DELIMS 89 | BASH_TPL_STMT_DELIM 90 | BASH_TPL_STMT_BLOCK_DELIMS 91 | BASH_TPL_TEXT_DELIM 92 | BASH_TPL_DIR_DELIM 93 | BASH_TPL_CMT_DELIM 94 | 95 | example: 96 | $ echo 'Hello <% \$NAME %>' > test.tpl 97 | $ NAME="Chuck Norris" source <( bash-tpl test.tpl ) 98 | 99 | Hello Chuck Norris 100 | 101 | learn more: https://github.com/TekWizely/bash-tpl 102 | 103 | USAGE 104 | } 105 | 106 | ####################################################################### 107 | # Delim Functions 108 | ####################################################################### 109 | 110 | TAG_DELIM_REGEX='^([^[:blank:]])([^[:blank:]]) ([^[:blank:]])([^[:blank:]])$' 111 | TAG_STMT_DELIM_REGEX='^([^[:blank:]])$' 112 | TAG_FMT_DELIM_REGEX='^([^[:blank:]]) ([^[:blank:]])$' 113 | STMT_DELIM_REGEX='^([^[:blank:]]+)$' 114 | STMT_BLOCK_DELIM_REGEX='^([^[:blank:]]+) ([^[:blank:]]+)$' 115 | STMT_BLOCK_TEXT_REGEX='^([^[:blank:]]+\ ?)$' # Optional trailing ' ' 116 | 117 | ## 118 | # reset_delims 119 | # 120 | function reset_delims() { 121 | TAG_START_DELIM1='<' 122 | TAG_START_DELIM2='%' 123 | TAG_STOP_DELIM1='%' 124 | TAG_STOP_DELIM2='>' 125 | 126 | TAG_STMT_DELIM='%' 127 | 128 | TAG_FMT_START_DELIM='|' 129 | TAG_FMT_STOP_DELIM='|' 130 | 131 | STMT_DELIM='%' 132 | 133 | TEXT_DELIM_UNDEFINED=1 134 | TEXT_DELIM='' 135 | 136 | STMT_BLOCK_DELIM_UNDEFINED=1 137 | STMT_BLOCK_START_DELIM='' 138 | STMT_BLOCK_STOP_DELIM='' 139 | 140 | DIRECTIVE_DELIM='.' 141 | 142 | COMMENT_DELIM_UNDEFINED=1 143 | COMMENT_DELIM='' 144 | } 145 | 146 | ## 147 | # parse_tag_delims 148 | # $1 = delims 149 | # $2 = src (for error msg) 150 | # 151 | function parse_tag_delims() { 152 | if [[ "${1}" =~ $TAG_DELIM_REGEX ]]; then 153 | TAG_START_DELIM1="${BASH_REMATCH[1]}" 154 | TAG_START_DELIM2="${BASH_REMATCH[2]}" 155 | TAG_STOP_DELIM1="${BASH_REMATCH[3]}" 156 | TAG_STOP_DELIM2="${BASH_REMATCH[4]}" 157 | else 158 | echo "Error: Invalid or missing tag delimiter values for ${2-tag delims}: '${1}'" >&2 159 | exit 1 160 | fi 161 | } 162 | 163 | ## 164 | # parse_tag_stmt_delims 165 | # $1 = delim 166 | # $2 = src (for error msg) 167 | # 168 | function parse_tag_stmt_delim() { 169 | if [[ "${1}" =~ $TAG_STMT_DELIM_REGEX ]]; then 170 | TAG_STMT_DELIM="${BASH_REMATCH[1]}" 171 | else 172 | echo "Error: Invalid or missing tag stmt delimiter value for ${2-tag stmt delim}: '${1}'" >&2 173 | exit 1 174 | fi 175 | } 176 | 177 | ## 178 | # parse_tag_fmt_delims 179 | # $1 = delims 180 | # $2 = src (for error msg) 181 | # 182 | function parse_tag_fmt_delims() { 183 | if [[ "${1}" =~ $TAG_FMT_DELIM_REGEX ]]; then 184 | TAG_FMT_START_DELIM="${BASH_REMATCH[1]}" 185 | TAG_FMT_STOP_DELIM="${BASH_REMATCH[2]}" 186 | else 187 | echo "Error: Invalid or missing tag fmt delimiter values for ${2-tag fmt delims}: '${1}'" >&2 188 | exit 1 189 | fi 190 | } 191 | 192 | ## 193 | # parse_stmt_delim 194 | # $1 = delim 195 | # $2 = src (for error msg) 196 | # 197 | function parse_stmt_delim() { 198 | if [[ "${1}" =~ $STMT_DELIM_REGEX ]]; then 199 | STMT_DELIM="${BASH_REMATCH[1]}" 200 | else 201 | echo "Error: Invalid or missing stmt delimiter value for ${2:-stmt delim}: '${1}'" >&2 202 | exit 1 203 | fi 204 | } 205 | 206 | ## 207 | # parse_stmt_block_delims 208 | # $1 = delims 209 | # $2 = src (for error msg) 210 | # 211 | function parse_stmt_block_delims() { 212 | if [[ "${1}" =~ $STMT_BLOCK_DELIM_REGEX ]]; then 213 | STMT_BLOCK_START_DELIM="${BASH_REMATCH[1]}" 214 | STMT_BLOCK_STOP_DELIM="${BASH_REMATCH[2]}" 215 | STMT_BLOCK_DELIM_UNDEFINED='' 216 | else 217 | echo "Error: Invalid or missing stmt-block delimiter values for ${2:-stmt-block delims}: '${1}'" >&2 218 | exit 1 219 | fi 220 | } 221 | 222 | ## 223 | # parse_text_delim - Uses STMT delim regex 224 | # $1 = delim 225 | # $2 = src (for error msg) 226 | # 227 | function parse_text_delim() { 228 | if [[ "${1}" =~ $STMT_BLOCK_TEXT_REGEX ]]; then 229 | TEXT_DELIM="${1}" 230 | TEXT_DELIM_UNDEFINED='' 231 | else 232 | echo "Error: Invalid or missing text delimiter value for ${2:-txt delim}: '${1}'" >&2 233 | exit 1 234 | fi 235 | } 236 | 237 | ## 238 | # parse_directive_delim - Uses STMT delim regex 239 | # $1 = delim 240 | # $2 = src (for error msg) 241 | # 242 | function parse_directive_delim() { 243 | if [[ "${1}" =~ $STMT_DELIM_REGEX ]]; then 244 | DIRECTIVE_DELIM="${1}" 245 | else 246 | echo "Error: Invalid or missing directive delimiter value for ${2:-dir delim}: '${1}'" >&2 247 | exit 1 248 | fi 249 | } 250 | 251 | ## 252 | # parse_comment_delim - Uses STMT delim regex 253 | # $1 = delim 254 | # $2 = src (for error msg) 255 | # 256 | function parse_comment_delim() { 257 | if [[ "${1}" =~ $STMT_DELIM_REGEX ]]; then 258 | COMMENT_DELIM="${1}" 259 | COMMENT_DELIM_UNDEFINED='' 260 | else 261 | echo "Error: Invalid or missing comment delimiter value for ${2:-cmt delim}: '${1}'" >&2 262 | exit 1 263 | fi 264 | } 265 | 266 | ## 267 | # reset_template_regexes 268 | # 269 | function reset_template_regexes() { 270 | # Fixup STMT_BLOCK delims - Default to STMT_DELIM if not set 271 | # 272 | if [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]]; then 273 | STMT_BLOCK_START_DELIM="${STMT_DELIM}" 274 | STMT_BLOCK_STOP_DELIM="${STMT_DELIM}" 275 | fi 276 | 277 | # Fixup TEXT delim - Default to STMT_DELIM followed by ' ' if not set 278 | # 279 | if [[ -n "${TEXT_DELIM_UNDEFINED}" ]]; then 280 | TEXT_DELIM="${STMT_DELIM} " # Note trailing space (' ') 281 | fi 282 | 283 | # Fixup COMMENT delim - Default to STMT_DELIM followed by '#' if not set 284 | # 285 | if [[ -n "${COMMENT_DELIM_UNDEFINED}" ]]; then 286 | COMMENT_DELIM="${STMT_DELIM}#" 287 | fi 288 | 289 | # 290 | # Create regexes 291 | # 292 | 293 | local d ds d1 d1_ d2 d2_ d3 d3_ d4 d4_ f1 f2 f2_ 294 | 295 | d="${DIRECTIVE_DELIM}" 296 | escape_regex d 297 | DIRECTIVE_REGEX="^([[:blank:]]*)${d}([a-zA-Z_-]+\??)(.*)\$" 298 | 299 | d="${COMMENT_DELIM}" 300 | escape_regex d 301 | COMMENT_REGEX="^([[:blank:]]*)${d}" 302 | 303 | d="${STMT_DELIM}" 304 | escape_regex d 305 | STATEMENT_REGEX="^([[:blank:]]*)${d}[[:blank:]]+(.+)\$" 306 | 307 | d="${STMT_BLOCK_START_DELIM}" 308 | escape_regex d 309 | STATEMENT_BLOCK_START_REGEX="^([[:blank:]]*)${d}[[:blank:]]*\$" 310 | 311 | d="${STMT_BLOCK_STOP_DELIM}" 312 | escape_regex d 313 | STATEMENT_BLOCK_STOP_REGEX="^([[:blank:]]*)${d}[[:blank:]]*\$" 314 | 315 | d="${TEXT_DELIM}" 316 | escape_regex d 317 | STATEMENT_BLOCK_TEXT_REGEX="^([[:blank:]]*)${d}([[:blank:]]*[^[:blank:]](.*))\$" 318 | 319 | TEXT_REGEX='^([[:blank:]]*)([^[:blank:]](.*))?$' 320 | 321 | d1="${TAG_START_DELIM1}" 322 | d1_="${d1}" 323 | escape_regex d1 324 | 325 | d2="${TAG_START_DELIM2}" 326 | d2_="${d2}" 327 | escape_regex d2 328 | 329 | d3="${TAG_STOP_DELIM1}" 330 | d3_="${d3}" 331 | escape_regex d3 332 | 333 | d4="${TAG_STOP_DELIM2}" 334 | d4_="${d4}" 335 | escape_regex d4 336 | 337 | ds="${TAG_STMT_DELIM}" 338 | escape_regex ds 339 | 340 | f1="${TAG_FMT_START_DELIM}" 341 | escape_regex f1 342 | 343 | f2="${TAG_FMT_STOP_DELIM}" 344 | f2_="${f2}" 345 | escape_regex f2 346 | 347 | local fmt_regex std_regex quote_regex stmt_regex 348 | 349 | fmt_regex="${f1}([^${f2_}]*)${f2}" 350 | 351 | TAG_TEXT_REGEX="^([^${d1_}]+|${d1}$|${d1}[^${d1_}${d2_}]+)(.*)" 352 | 353 | std_regex="((([^${d3_}])|(${d3}[^${d4_}]))*)" 354 | 355 | # No [[:space:]] checks after fmt_regex as we'll let std_regex pick them up then trim them 356 | TAG_STD_REGEX="^${d1}${d2}[[:space:]]*(${fmt_regex})?${std_regex}${d3}${d4}(.*)" 357 | TAG_STD_MATCH_IDX_FMT=2 358 | TAG_STD_MATCH_IDX_TXT=3 359 | TAG_STD_MATCH_IDX_END=7 360 | 361 | quote_regex="\"((([^\"])|(\"[^${d3_}])|(\"${d3}[^${d4_}]))*)\"" 362 | 363 | TAG_QUOTE_REGEX="^${d1}${d2}[[:space:]]*(${fmt_regex})?[[:space:]]*${quote_regex}[[:space:]]*${d3}${d4}(.*)" 364 | TAG_QUOTE_MATCH_IDX_FMT=2 365 | TAG_QUOTE_MATCH_IDX_TXT=3 366 | TAG_QUOTE_MATCH_IDX_END=8 367 | 368 | stmt_regex="${ds}((([^${d3_}])|(${d3}[^${d4_}]))*)" 369 | 370 | # No trailing [[:space:]] check as we'll let std_regex pick them up then trim them 371 | TAG_STATEMENT_REGEX="^${d1}${d2}[[:space:]]*(${fmt_regex})?[[:space:]]*${stmt_regex}${d3}${d4}(.*)" 372 | TAG_STATEMENT_MATCH_IDX_FMT=2 373 | TAG_STATEMENT_MATCH_IDX_TXT=3 374 | TAG_STATEMENT_MATCH_IDX_END=7 375 | 376 | # printf "# ---> delim regexes:" 377 | # printf "# STATEMENT_BLOCK_START_REGEX: '%s'\n" "${STATEMENT_BLOCK_START_REGEX}" 378 | # printf "# STATEMENT_BLOCK_STOP_REGEX: '%s'\n" "${STATEMENT_BLOCK_STOP_REGEX}" 379 | # printf "# COMMENT_REGEX: '%s'\n" "${COMMENT_REGEX}" 380 | # printf "# DIRECTIVE_REGEX: '%s'\n" "${DIRECTIVE_REGEX}" 381 | # printf "# STATEMENT_REGEX: '%s'\n" "${STATEMENT_REGEX}" 382 | # printf "# TAG_TEXT_REGEX: '%s'\n" "${TAG_TEXT_REGEX}" 383 | # printf "# TAG_STD_REGEX: '%s'\n" "${TAG_STD_REGEX}" 384 | # printf "# TAG_QUOTE_REGEX: '%s'\n" "${TAG_QUOTE_REGEX}" 385 | # printf "# TAG_STATEMENT_REGEX: '%s'\n" "${TAG_STATEMENT_REGEX}" 386 | } 387 | 388 | ####################################################################### 389 | # Misc Functions 390 | ####################################################################### 391 | 392 | ## 393 | # trim 394 | # usage: trim varname 395 | # NOTE: Expects value to NOT contain '\n' 396 | # 397 | function trim() { 398 | read -r "$1" <<< "${!1}"$'\n' 399 | } 400 | ## 401 | # escape_string 402 | # Escapes value compatible with posix `printf %b` 403 | # usage: escape_string varname 404 | # 405 | function escape_string { 406 | local e="${!1}" 407 | # Escape '\' first since we'll be adding more later 408 | # Octal support = \0[0-9]{0,3} 409 | e="${e//\\/\\\\}" 410 | e="${e//\'/\\0047}" 411 | e="${e//$'\a'/\\a}" 412 | e="${e//$'\b'/\\b}" 413 | e="${e//$'\f'/\\f}" 414 | e="${e//$'\n'/\\n}" 415 | e="${e//$'\r'/\\r}" 416 | e="${e//$'\t'/\\t}" 417 | e="${e//$'\v'/\\v}" 418 | printf -v "${1}" "'%s'" "${e}" 419 | } 420 | 421 | ## 422 | # escape_regex 423 | # usage: escape_regex varname 424 | # 425 | function escape_regex() { 426 | local e="${!1}" 427 | # Escape '\' first since we'll be adding more after 428 | e="${e//\\/\\\\}" 429 | e="${e//'$'/\\$}" 430 | e="${e//'*'/\\*}" 431 | e="${e//'+'/\\+}" 432 | e="${e//'.'/\\.}" 433 | e="${e//'?'/\\?}" 434 | e="${e//'^'/\\^}" 435 | e="${e//'|'/\\|}" 436 | e="${e//'('/\\(}" 437 | e="${e//')'/\\)}" 438 | e="${e//'['/\\[}" 439 | e="${e//']'/\\]}" 440 | e="${e//'{'/\\{}" 441 | local RBRACE='}' 442 | e="${e//'}'/\\${RBRACE}}" 443 | printf -v "${1}" "%s" "${e}" 444 | } 445 | 446 | ## 447 | # normalize_directive 448 | # usage: normalize_directive varname 449 | # 450 | function normalize_directive() { 451 | local result 452 | # shellcheck disable=SC2034 # ref is used 453 | result=$(tr 'a-z_' 'A-Z-' <<< "${!1}") 454 | printf -v "${1}" "%s" "${result}" 455 | } 456 | 457 | ####################################################################### 458 | # STATES 459 | ####################################################################### 460 | 461 | STATES=() # empty => DEFAULT 462 | STATE="DEFAULT" # [ DEFAULT, MAYBE_TXT_BLOCK, TXT_BLOCK, START_STMT_BLOCK, STMT_BLOCK ] 463 | 464 | ## 465 | # push_state 466 | # 467 | function push_state() { 468 | STATES+=("${STATE}") 469 | STATE="${1}" 470 | } 471 | 472 | ## 473 | # pop_state 474 | # 475 | function pop_state() { 476 | if [[ ${#STATES[@]} -gt 0 ]]; then 477 | STATE="${STATES[${#STATES[@]} - 1]}" 478 | unset "STATES[${#STATES[@]}-1]" 479 | else 480 | STATE="DEFAULT" 481 | fi 482 | } 483 | 484 | ####################################################################### 485 | # TEXT_INDENTS 486 | ####################################################################### 487 | 488 | TEXT_INDENTS=() # empty => "" 489 | TEXT_INDENT="" 490 | 491 | ## 492 | # push_text_indent 493 | # 494 | function push_text_indent() { 495 | TEXT_INDENTS+=("${TEXT_INDENT}") 496 | TEXT_INDENT="${1}" 497 | } 498 | 499 | ## 500 | # pop_text_indent 501 | # 502 | function pop_text_indent() { 503 | if [[ ${#TEXT_INDENTS[@]} -gt 0 ]]; then 504 | TEXT_INDENT="${TEXT_INDENTS[${#TEXT_INDENTS[@]} - 1]}" 505 | unset "TEXT_INDENTS[${#TEXT_INDENTS[@]} - 1]" 506 | else 507 | TEXT_INDENT="" 508 | fi 509 | } 510 | 511 | ####################################################################### 512 | # STATEMENT_INDENTS 513 | ####################################################################### 514 | 515 | STATEMENT_INDENTS=() # empty => "" 516 | STATEMENT_INDENT="" 517 | 518 | ## 519 | # push_statement_indent 520 | # 521 | function push_statement_indent() { 522 | STATEMENT_INDENTS+=("${STATEMENT_INDENT}") 523 | STATEMENT_INDENT="${1}" 524 | } 525 | 526 | ## 527 | # pop_statement_indent 528 | # 529 | function pop_statement_indent() { 530 | if [[ ${#STATEMENT_INDENTS[@]} -gt 0 ]]; then 531 | STATEMENT_INDENT="${STATEMENT_INDENTS[${#STATEMENT_INDENTS[@]} - 1]}" 532 | unset "STATEMENT_INDENTS[${#STATEMENT_INDENTS[@]} - 1]" 533 | else 534 | STATEMENT_INDENT="" 535 | fi 536 | } 537 | 538 | ####################################################################### 539 | # BLOCK_INDENTS 540 | ####################################################################### 541 | 542 | BLOCK_INDENTS=() # empty => "" 543 | BLOCK_INDENT="" 544 | 545 | ## 546 | # push_block_indent 547 | # 548 | function push_block_indent() { 549 | BLOCK_INDENTS+=("${BLOCK_INDENT}") 550 | BLOCK_INDENT="${1}" 551 | } 552 | 553 | ## 554 | # pop_block_indent 555 | # 556 | function pop_block_indent() { 557 | if [[ ${#BLOCK_INDENTS[@]} -gt 0 ]]; then 558 | BLOCK_INDENT="${BLOCK_INDENTS[${#BLOCK_INDENTS[@]} - 1]}" 559 | unset "BLOCK_INDENTS[${#BLOCK_INDENTS[@]} - 1]" 560 | else 561 | BLOCK_INDENT="" 562 | fi 563 | } 564 | 565 | ####################################################################### 566 | # Print Functions 567 | ####################################################################### 568 | 569 | ## 570 | # print_statement 571 | # $1 = leading indentation 572 | # $2 = statement 573 | # 574 | function print_statement() { 575 | local indent="${1}" 576 | if [[ "${indent}" == "${BLOCK_INDENT}"* ]]; then 577 | indent="${indent/#$BLOCK_INDENT/}" 578 | fi 579 | printf "%s\n" "${BASE_STMT_INDENT}${STATEMENT_INDENT}${indent}${2}" 580 | } 581 | 582 | ## 583 | # print_text - generates a printf statement for template text 584 | # $1 = leading text indentation 585 | # $2 = text 586 | # $3 = leading stmt indentation [OPTIONAL] 587 | # 588 | function print_text() { 589 | local indent="${1}" 590 | if [[ "${indent}" == "${BLOCK_INDENT}"* ]]; then 591 | indent="${indent/#$BLOCK_INDENT/}" 592 | fi 593 | process_tags "${3-${BLOCK_INDENT}}" "${BASE_TEXT_INDENT}${TEXT_INDENT}${indent}${2}" 594 | } 595 | 596 | ####################################################################### 597 | # Process Functions 598 | ####################################################################### 599 | 600 | ## 601 | # process_tags 602 | # $1 = statement indentation 603 | # $2 = full line of text to process 604 | # 605 | function process_tags() { 606 | local stmt_indent line formats args fmt arg quoted 607 | stmt_indent="${1}" 608 | line="${2}" 609 | formats="" 610 | args=() 611 | while [ -n "${line}" ]; do 612 | # echo "# LINE @ START: $(declare -p line)" >&2 613 | if [[ "${line}" =~ $TAG_TEXT_REGEX ]]; then 614 | # echo "# TEXT TAG MATCH: $(declare -p BASH_REMATCH)" >&2 615 | quoted="${BASH_REMATCH[1]}" 616 | escape_string quoted 617 | #printf -v quoted "%q" "${BASH_REMATCH[1]}" 618 | formats="${formats}%b" 619 | args+=("${quoted}") 620 | line="${BASH_REMATCH[2]}" 621 | elif [[ "${line}" =~ $TAG_QUOTE_REGEX ]]; then 622 | # echo "# QUOTE TAG MATCH: $(declare -p BASH_REMATCH)" >&2 623 | fmt="${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" 624 | trim fmt 625 | arg="${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" 626 | formats="${formats}${fmt:-%s}" 627 | args+=("\"${arg}\"") 628 | line="${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" 629 | elif [[ "${line}" =~ $TAG_STATEMENT_REGEX ]]; then 630 | # echo "# STMT TAG MATCH: $(declare -p BASH_REMATCH)" >&2 631 | fmt="${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" 632 | trim fmt 633 | arg="${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" 634 | trim arg 635 | formats="${formats}${fmt:-%s}" 636 | args+=("\"\$(${arg})\"") 637 | line="${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" 638 | # Check standard regex last as it's a super-set of quote and stmt regex 639 | # But check fmt regex first 640 | elif [[ "${line}" =~ $TAG_STD_REGEX ]]; then 641 | # echo "# STD TAG MATCH: $(declare -p BASH_REMATCH)" >&2 642 | fmt="${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" 643 | trim fmt 644 | arg="${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" 645 | trim arg 646 | formats="${formats}${fmt:-%s}" 647 | args+=("\"${arg}\"") 648 | line="${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" 649 | # Assume next character is TEXT - extract and process remainder 650 | # 651 | elif [[ "${line}" =~ (.)(.*) ]]; then 652 | # echo "# DEFAULT: Assuming first char is TEXT: $(declare -p line)" >&2 653 | quoted="${BASH_REMATCH[1]}" 654 | escape_string quoted 655 | #printf -v quoted "%q" "${BASH_REMATCH[1]}" 656 | formats="${formats}%b" 657 | args+=("${quoted}") 658 | line="${BASH_REMATCH[2]}" 659 | fi 660 | # echo "# LINE @ END: $(declare -p line)" >&2 661 | done 662 | local stmt 663 | if [[ ${#args[@]} -gt 0 ]]; then 664 | printf -v stmt "printf \"%s\\\\n\" %s" "${formats}" "${args[*]}" 665 | else 666 | printf -v stmt "printf \"\\\\n\"" 667 | fi 668 | print_statement "${stmt_indent}" "${stmt}" 669 | } 670 | 671 | DELIM_DIR_TAG_REGEX='[Tt][Aa][Gg]\s*=\s*"([^"]*)"' 672 | DELIM_DIR_TAG_STMT_REGEX='[Tt][Aa][Gg][_-]?[Ss][Tt][Mm][Tt]\s*=\s*"([^"]*)"' 673 | DELIM_DIR_TAG_FMT_REGEX='[Tt][Aa][Gg][_-]?[Ff][Mm][Tt]\s*=\s*"([^"]*)"' 674 | DELIM_DIR_STMT_REGEX='[Ss][Tt][Mm][Tt]\s*=\s*"([^"]*)"' 675 | DELIM_DIR_STMT_BLOCK_REGEX='[Ss][Tt][Mm][Tt][_-]?[Bb][Ll][Oo][Cc][Kk]\s*=\s*"([^"]*)"' 676 | DELIM_DIR_TXT_REGEX='[Tt][Xx][Tt]\s*=\s*"([^"]*)"' 677 | DELIM_DIR_TEXT_REGEX='[Tt][Ee][Xx][Tt]\s*=\s*"([^"]*)"' 678 | DELIM_DIR_DIR_REGEX='[Dd][Ii][Rr]\s*=\s*"([^"]*)"' 679 | DELIM_DIR_DIRECTIVE_REGEX='[Dd][Ii][Rr][Ee][Cc][Tt][Ii][Vv][Ee]\s*=\s*"([^"]*)"' 680 | DELIM_DIR_CMT_REGEX='[Cc][Mm][Tt]\s*=\s*"([^"]*)"' 681 | DELIM_DIR_COMMENT_REGEX='[Cc][Oo][Mm][Mm][Ee][Nn][Tt]\s*=\s*"([^"]*)"' 682 | 683 | ## 684 | # process_directive 685 | # $1 = leading_indent 686 | # $2 = directive 687 | # $3 = directive arg(s) 688 | # 689 | function process_directive() { 690 | local directive 691 | directive="${2}" 692 | normalize_directive directive 693 | case "${directive}" in 694 | INCLUDE | INCLUDE\?) 695 | local file_not_found_ok="" 696 | if [ "${directive}" = "INCLUDE?" ]; then 697 | file_not_found_ok="1" 698 | fi 699 | local indent="${1}" 700 | if [[ "${indent}" == "${BLOCK_INDENT}"* ]]; then 701 | indent="${indent/#$BLOCK_INDENT/}" 702 | fi 703 | local args args_arr 704 | args="${3}" 705 | trim args 706 | declare -a args_arr="(${args})" 707 | # shellcheck disable=SC2128 # We choose BASH_SOURCE vs BASH_SOURCE[0] for compatability 708 | "${BASH_SOURCE}" \ 709 | --text-indent "${BASE_TEXT_INDENT}${TEXT_INDENT}${indent}" \ 710 | --stmt-indent "${BASE_STMT_INDENT}${STATEMENT_INDENT}${indent}" \ 711 | --block-indent "${BASE_BLOCK_INDENT}${BLOCK_INDENT}" \ 712 | --tag-delims "${TAG_START_DELIM1}${TAG_START_DELIM2} ${TAG_STOP_DELIM1}${TAG_STOP_DELIM2}" \ 713 | --tag-stmt-delim "${TAG_STMT_DELIM}" \ 714 | --tag-fmt-delims "${TAG_FMT_START_DELIM} ${TAG_FMT_STOP_DELIM}" \ 715 | --stmt-delim "${STMT_DELIM}" \ 716 | --stmt-block-delims "${STMT_BLOCK_START_DELIM} ${STMT_BLOCK_STOP_DELIM}" \ 717 | --txt-delim "${TEXT_DELIM}" \ 718 | --dir-delim "${DIRECTIVE_DELIM}" \ 719 | --cmt-delim "${COMMENT_DELIM}" \ 720 | ${file_not_found_ok:+'--file-not-found-ok'} \ 721 | "${args_arr[@]}" 722 | ;; 723 | DELIMS) 724 | # TAG 725 | # 726 | if [[ "${3}" =~ $DELIM_DIR_TAG_REGEX ]]; then 727 | parse_tag_delims "${BASH_REMATCH[1]}" 'DELIMS TAG directive' 728 | fi 729 | # TAG-STMT 730 | # 731 | if [[ "${3}" =~ $DELIM_DIR_TAG_STMT_REGEX ]]; then 732 | parse_tag_stmt_delim "${BASH_REMATCH[1]}" 'DELIMS TAG-STMT directive' 733 | fi 734 | # TAG-FMT 735 | # 736 | if [[ "${3}" =~ $DELIM_DIR_TAG_FMT_REGEX ]]; then 737 | parse_tag_fmt_delims "${BASH_REMATCH[1]}" 'DELIMS TAG-FMT directive' 738 | fi 739 | # STMT 740 | # 741 | if [[ "${3}" =~ $DELIM_DIR_STMT_REGEX ]]; then 742 | parse_stmt_delim "${BASH_REMATCH[1]}" 'DELIMS STMT directive' 743 | fi 744 | # STMT-BLOCK 745 | # 746 | if [[ "${3}" =~ $DELIM_DIR_STMT_BLOCK_REGEX ]]; then 747 | parse_stmt_block_delims "${BASH_REMATCH[1]}" '"DELIMS STMT-BLOCK directive' 748 | fi 749 | # TEXT 750 | # 751 | if [[ "${3}" =~ $DELIM_DIR_TXT_REGEX || "${3}" =~ $DELIM_DIR_TEXT_REGEX ]]; then 752 | parse_text_delim "${BASH_REMATCH[1]}" 'DELIMS TEXT directive' 753 | fi 754 | # DIRECTIVE 755 | # 756 | if [[ "${3}" =~ $DELIM_DIR_DIR_REGEX || "${3}" =~ $DELIM_DIR_DIRECTIVE_REGEX ]]; then 757 | parse_directive_delim "${BASH_REMATCH[1]}" 'DELIMS DIR directive' 758 | fi 759 | # COMMENT 760 | # 761 | if [[ "${3}" =~ $DELIM_DIR_CMT_REGEX || "${3}" =~ $DELIM_DIR_COMMENT_REGEX ]]; then 762 | parse_comment_delim "${BASH_REMATCH[1]}" 'DELIMS CMT directive' 763 | fi 764 | # Apply changes 765 | # 766 | reset_template_regexes 767 | ;; 768 | RESET-DELIMS) 769 | reset_delims 770 | reset_template_regexes 771 | ;; 772 | *) # unsupported directive 773 | echo "Error: Unknown directive: '${directive}' - Skipping" >&2 774 | ;; 775 | esac 776 | } 777 | 778 | function debug_array() { 779 | printf "[" 780 | local need_comma="" 781 | while [[ ${#@} -gt 0 ]]; do 782 | if [ -n "${need_comma:-}" ]; then 783 | printf ", " 784 | fi 785 | if [ -n "${1:-}" ]; then 786 | printf "'%q'" "${1}" 787 | else 788 | printf "''" 789 | fi 790 | need_comma=1 791 | shift 792 | done 793 | printf "]" 794 | } 795 | ## 796 | # debug_state logs the state of the global variables. 797 | # To use this set the BASH_TPL_DEBUG variable to a non-empty value 798 | # when invoking the script. 799 | # TODO Track source input file+line numbers 800 | # $1 = template line | EOF 801 | # 802 | function debug_state() { 803 | printf "#<< ---------------\n" 804 | printf "#LINE TEXT : '%s'\n" "${1-}" 805 | printf "#STATE : %s\n" "${STATE:-}" 806 | printf "#STATES : %s\n" "$(debug_array "${STATES[@]}")" 807 | printf "#TEXT_INDENT : %q\n" "${TEXT_INDENT:-}" 808 | printf "#TEXT_INDENTS : %s\n" "$(debug_array "${TEXT_INDENTS[@]}")" 809 | printf "#STATEMENT_INDENT : %q\n" "${STATEMENT_INDENT:-}" 810 | printf "#STATEMENT_INDENTS: %s\n" "$(debug_array "${STATEMENT_INDENTS[@]}")" 811 | printf "#BLOCK_INDENT : %q\n" "${BLOCK_INDENT:-}" 812 | printf "#BLOCK_INDENTS : %s\n" "$(debug_array "${BLOCK_INDENTS[@]}")" 813 | printf "#TEXT_BLOCK_LINES_INDENT : %q\n" "${TEXT_BLOCK_LINES_INDENT}" 814 | printf "#TEXT_BLOCK_LINES_INDENT_SET : %q\n" "${TEXT_BLOCK_LINES_INDENT_SET}" 815 | printf "#STATEMENT_BLOCK_LINES_INDENT : %q\n" "${STATEMENT_BLOCK_LINES_INDENT}" 816 | printf "#STATEMENT_BLOCK_LINES_INDENT_STATE : %q\n" "${STATEMENT_BLOCK_LINES_INDENT_STATE}" 817 | printf "#>> ---------------\n" 818 | } 819 | 820 | function process_line() { 821 | [ -n "${BASH_TPL_DEBUG:-}" ] && debug_state ${@+"$@"} 822 | state_"${STATE}" ${@+"$@"} 823 | } 824 | 825 | function process_stdin() { 826 | local line 827 | while IFS="" read -r line || [ -n "${line}" ]; do 828 | process_line "${line}" 829 | done 830 | # EOF - Notify states 831 | # Call with no args 832 | # 833 | while [[ "${STATE}" != "DEFAULT" ]]; do 834 | process_line 835 | done 836 | process_line # DEFAULT 837 | } 838 | 839 | ####################################################################### 840 | # State Handler Functions 841 | ####################################################################### 842 | 843 | ## 844 | # state_DEFAULT 845 | # Not inside any blocks 846 | # Assumes *_INDENT and STATE arrays are empty 847 | # 848 | function state_DEFAULT() { 849 | [[ ${#@} -gt 0 ]] || return # Exit early on EOF 850 | # Line is a statement 851 | # 852 | if [[ "${1}" =~ $STATEMENT_REGEX ]]; then 853 | print_statement "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" 854 | push_statement_indent "${BASH_REMATCH[1]}" 855 | push_state "MAYBE_TXT_BLOCK" 856 | # Line is a statement block start 857 | # 858 | elif [[ "${1}" =~ $STATEMENT_BLOCK_START_REGEX ]]; then 859 | push_statement_indent "${BASH_REMATCH[1]}" 860 | push_state "START_STMT_BLOCK" 861 | # Line is a directive 862 | # 863 | elif [[ "${1}" =~ $DIRECTIVE_REGEX ]]; then 864 | process_directive "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" 865 | # Line is a comment 866 | # 867 | elif [[ "${1}" =~ $COMMENT_REGEX ]]; then 868 | : # Comments do not generate output 869 | # Line is text 870 | # NOTE : Check LAST because regex always matches 871 | # 872 | elif [[ "${1}" =~ $TEXT_REGEX ]]; then 873 | print_text "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" 874 | fi 875 | } 876 | 877 | TEXT_BLOCK_LINES=() 878 | TEXT_BLOCK_LINES_INDENT="" 879 | TEXT_BLOCK_LINES_INDENT_SET="" 880 | 881 | ## 882 | # state_MAYBE_TXT_BLOCK 883 | # Previous line was a statement 884 | # We might be starting a text block 885 | # NOTE: Assumes 886 | # push_state "MAYBE_TXT_BLOCK" 887 | # push_statement_indent 888 | # 889 | function state_MAYBE_TXT_BLOCK() { 890 | # If there's a line to process (i.e. not EOF) 891 | # 892 | if [[ ${#@} -gt 0 ]]; then 893 | # Current line is empty 894 | # Considered text block content, 895 | # but doesn't contribute to indentation tracking 896 | # 897 | if [[ "${1}" == "" ]]; then 898 | TEXT_BLOCK_LINES+=("${1}") # Save line 899 | return 900 | # Current line is a block-end statement, 901 | # i.e. it's a statement at the same indentation as the start statement 902 | # 903 | elif [[ "${1}" =~ $STATEMENT_REGEX && "${BASH_REMATCH[1]}" == "${STATEMENT_INDENT}" ]]; then 904 | # We've saved a FULL text block ! 905 | # Use computed indentation 906 | # 907 | push_text_indent "${TEXT_INDENT}${STATEMENT_INDENT/#$BLOCK_INDENT/}" # Additive 908 | push_statement_indent "${TEXT_BLOCK_LINES_INDENT}" 909 | push_block_indent "${TEXT_BLOCK_LINES_INDENT}" 910 | local state_marker=${#STATES[@]} # Save for cleanup 911 | push_state "TXT_BLOCK" 912 | # Text blocks can be nested, so save lines and cleanup *before* processing 913 | # 914 | local lines=("${TEXT_BLOCK_LINES[@]}") 915 | TEXT_BLOCK_LINES=() 916 | TEXT_BLOCK_LINES_INDENT="" 917 | TEXT_BLOCK_LINES_INDENT_SET="" 918 | # Process saved lines now in new state 919 | # 920 | local line 921 | for line in "${lines[@]}"; do 922 | process_line "${line}" 923 | done 924 | # Clean up our TXT_BLOCK state and any other danglers 925 | # 926 | while [[ ${#STATES[@]} -gt $state_marker ]]; do 927 | process_line # EOF 928 | done 929 | # Clean up our MAYBE_TXT_BLOCK state 930 | # 931 | pop_statement_indent 932 | pop_state 933 | # Process close block in parent context 934 | # 935 | process_line "${1}" 936 | return 937 | # Capture line indentation for tracking 938 | # TEXT_REGEX is perfect for this, so just re-use it 939 | # NOTE: Regex always matches 940 | # 941 | elif [[ "${1}" =~ $TEXT_REGEX ]]; then 942 | TEXT_BLOCK_LINES+=("${1}") # Save line 943 | # If current line is indented 944 | # 945 | if [[ "${BASH_REMATCH[1]}" != "${STATEMENT_INDENT}" && "${BASH_REMATCH[1]}" == "${STATEMENT_INDENT}"* ]]; then 946 | # If first time through 947 | # 948 | if [[ "${TEXT_BLOCK_LINES_INDENT_SET}" == "" ]]; then 949 | # Track current indentation 950 | # 951 | TEXT_BLOCK_LINES_INDENT="${BASH_REMATCH[1]}" 952 | TEXT_BLOCK_LINES_INDENT_SET="1" 953 | return 954 | # If current line is indented SAME OR LESS than tracked 955 | # 956 | elif [[ "${TEXT_BLOCK_LINES_INDENT}" == "${BASH_REMATCH[1]}"* ]]; then 957 | # Update tracked indentation (may set to same value) 958 | # 959 | TEXT_BLOCK_LINES_INDENT="${BASH_REMATCH[1]}" 960 | return 961 | # If current line is indented MORE than tracked 962 | # 963 | elif [[ "${BASH_REMATCH[1]}" == "${TEXT_BLOCK_LINES_INDENT}"* ]]; then 964 | # No change 965 | # 966 | return 967 | # Neither line is a subset of the other 968 | # 969 | else 970 | : # Here for completeness 971 | fi 972 | # Current line is NOT indented 973 | # 974 | else 975 | : # Here for completeness 976 | fi 977 | fi 978 | # EOF 979 | # 980 | else 981 | : # Fall through 982 | fi 983 | # If we haven't returned by now, then we're not in a text block 984 | # Discard saved state and process saved lines 985 | # 986 | pop_statement_indent 987 | pop_state 988 | # Text blocks can be nested, so save lines and cleanup *before* processing 989 | # 990 | local lines=("${TEXT_BLOCK_LINES[@]}") 991 | # Clean up 992 | # 993 | TEXT_BLOCK_LINES=() 994 | TEXT_BLOCK_LINES_INDENT="" 995 | TEXT_BLOCK_LINES_INDENT_SET="" 996 | # Process saved lines now in parent context 997 | # TODO "push" these back onto primary line-processing stream? 998 | # 999 | local line 1000 | for line in "${lines[@]}"; do 1001 | process_line "${line}" 1002 | done 1003 | } 1004 | 1005 | ## 1006 | # state_TXT_BLOCK 1007 | # NOTE: Assumes 1008 | # Called within MAYBE_TXT_BLOCK with a complete block to process 1009 | # Will NOT be called with TXT Block Close 1010 | # Every line has a minimum indentation of BLOCK_INDENT 1011 | # push_state TXT_BLOCK 1012 | # push_text_indent 1013 | # push_statement_indent 1014 | # push_block_indent 1015 | # 1016 | function state_TXT_BLOCK() { 1017 | # EOF 1018 | # 1019 | if [[ ${#@} -eq 0 ]]; then 1020 | # End of text block 1021 | # Discard saved state 1022 | # 1023 | pop_text_indent 1024 | pop_statement_indent 1025 | pop_block_indent 1026 | pop_state 1027 | # Current line is empty 1028 | # 1029 | elif [[ "${1}" == "" ]]; then 1030 | process_tags "${BLOCK_INDENT}" "" 1031 | # Current line is a statement 1032 | # 1033 | elif [[ "${1}" =~ $STATEMENT_REGEX ]]; then 1034 | print_statement "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" 1035 | push_statement_indent "${BASH_REMATCH[1]}" 1036 | push_state "MAYBE_TXT_BLOCK" 1037 | # Current line is a statement Start Block 1038 | # 1039 | elif [[ "${1}" =~ $STATEMENT_BLOCK_START_REGEX ]]; then 1040 | push_statement_indent "${BASH_REMATCH[1]}" 1041 | push_state "START_STMT_BLOCK" 1042 | # Current line is a directive 1043 | # 1044 | elif [[ "${1}" =~ $DIRECTIVE_REGEX ]]; then 1045 | process_directive "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" 1046 | # Line is a comment 1047 | # 1048 | elif [[ "${1}" =~ $COMMENT_REGEX ]]; then 1049 | : # Comments do not generate output 1050 | # Line is text 1051 | # NOTE: Regex always matches 1052 | # 1053 | elif [[ "${1}" =~ $TEXT_REGEX ]]; then 1054 | print_text "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" 1055 | fi 1056 | } 1057 | 1058 | STATEMENT_BLOCK_LINES=() 1059 | STATEMENT_BLOCK_LINES_INDENT="" 1060 | STATEMENT_BLOCK_LINES_INDENT_STATE="" 1061 | 1062 | ## 1063 | # state_START_STMT_BLOCK 1064 | # NOTE: Assumes 1065 | # push_state "START_STMT_BLOCK" 1066 | # push_statement_indent 1067 | # 1068 | function state_START_STMT_BLOCK() { 1069 | # If there's a line to process (i.e. not EOF) 1070 | # 1071 | if [[ ${#@} -gt 0 ]]; then 1072 | # Current line is empty 1073 | # Considered statement block content, 1074 | # but doesn't contribute to indentation tracking 1075 | # 1076 | if [[ "${1}" == "" ]]; then 1077 | STATEMENT_BLOCK_LINES+=("${1}") # Save line 1078 | return 1079 | # Current line is a statement block end 1080 | # 1081 | elif [[ "${1}" =~ $STATEMENT_BLOCK_STOP_REGEX ]]; then 1082 | # If indentation does not match block-open, then error 1083 | # TODO Track line numbers for better reporting 1084 | # 1085 | if [[ "${BASH_REMATCH[1]}" != "${STATEMENT_INDENT}" ]]; then 1086 | echo "Error: stmt-block close indentation does not match open" >&2 1087 | exit 1 1088 | fi 1089 | # We've saved a FULL statement block ! 1090 | # Is it fully indented? 1091 | # 1092 | if [[ "${STATEMENT_BLOCK_LINES_INDENT_STATE}" == "1" ]]; then 1093 | # Use computed indentation 1094 | # 1095 | push_text_indent "${TEXT_INDENT}${STATEMENT_INDENT/#$BLOCK_INDENT/}" # Additive 1096 | push_block_indent "${STATEMENT_BLOCK_LINES_INDENT}" 1097 | else 1098 | # If not consistently indented, default to no indent 1099 | # TODO Print warning? 1100 | # 1101 | push_text_indent "" 1102 | pop_statement_indent 1103 | push_statement_indent "" 1104 | push_block_indent "" 1105 | fi 1106 | # Process the saved lines 1107 | # NOTE: Statement block end (+ cleanup) will be processed by STMT_BLOCK handler 1108 | # 1109 | pop_state 1110 | push_state "STMT_BLOCK" 1111 | # Process saved lines now in new state 1112 | # Statement blocks do not nest, so we use global and cleanup *after* 1113 | # 1114 | local line 1115 | for line in "${STATEMENT_BLOCK_LINES[@]}"; do 1116 | process_line "${line}" 1117 | done 1118 | # Clean up our STMT_BLOCK state 1119 | # 1120 | process_line # EOF 1121 | # Clean up 1122 | # 1123 | STATEMENT_BLOCK_LINES=() 1124 | STATEMENT_BLOCK_LINES_INDENT="" 1125 | STATEMENT_BLOCK_LINES_INDENT_STATE="" 1126 | # Capture line indentation for tracking 1127 | # TEXT_REGEX is perfect for this, so just re-use it 1128 | # NOTE: Regex always matches 1129 | # 1130 | elif [[ "${1}" =~ $TEXT_REGEX ]]; then 1131 | STATEMENT_BLOCK_LINES+=("${1}") # Save line 1132 | # If current line is indented (or even) 1133 | # 1134 | if [[ "${BASH_REMATCH[1]}" == "${STATEMENT_INDENT}"* ]]; then 1135 | # If first time through 1136 | # 1137 | if [[ "${STATEMENT_BLOCK_LINES_INDENT_STATE}" == "" ]]; then 1138 | # Track current indentation 1139 | # 1140 | STATEMENT_BLOCK_LINES_INDENT="${BASH_REMATCH[1]}" 1141 | STATEMENT_BLOCK_LINES_INDENT_STATE="1" 1142 | # If still working with fully indented block 1143 | # 1144 | elif [[ "${STATEMENT_BLOCK_LINES_INDENT_STATE}" == "1" ]]; then 1145 | # If current line is indented SAME OR LESS than tracked 1146 | # 1147 | if [[ "${STATEMENT_BLOCK_LINES_INDENT}" == "${BASH_REMATCH[1]}"* ]]; then 1148 | # Update tracked indentation (may set to same value) 1149 | # 1150 | STATEMENT_BLOCK_LINES_INDENT="${BASH_REMATCH[1]}" 1151 | # If current line is indented MORE than tracked 1152 | # 1153 | elif [[ "${BASH_REMATCH[1]}" == "${STATEMENT_BLOCK_LINES_INDENT}"* ]]; then 1154 | # No change 1155 | # 1156 | : 1157 | # Neither line is a subset of the other 1158 | # 1159 | else 1160 | STATEMENT_BLOCK_LINES_INDENT_STATE="2" 1161 | fi 1162 | fi 1163 | # Current line is NOT indented (or even) 1164 | # 1165 | else 1166 | STATEMENT_BLOCK_LINES_INDENT_STATE="3" 1167 | fi 1168 | fi 1169 | # EOF 1170 | # 1171 | else 1172 | # EOF before close block reached is an error 1173 | # TODO Track line numbers for better reporting 1174 | # 1175 | echo "Error: Missing stmt-block close ('${STMT_BLOCK_STOP_DELIM}')" >&2 1176 | exit 1 1177 | fi 1178 | } 1179 | 1180 | ## 1181 | # state_STMT_BLOCK 1182 | # NOTE: Assumes 1183 | # Called within START_STMT_BLOCK with a complete block to process 1184 | # Will NOT be called with STMT Block Close 1185 | # push_state STMT_BLOCK 1186 | # push_text_indent 1187 | # push_statement_indent 1188 | # push_block_indent 1189 | # 1190 | function state_STMT_BLOCK() { 1191 | # EOF 1192 | # 1193 | if [[ ${#@} -eq 0 ]]; then 1194 | # End of statement block 1195 | # Discard saved state 1196 | # 1197 | pop_text_indent 1198 | pop_statement_indent 1199 | pop_block_indent 1200 | pop_state 1201 | # Current line is empty 1202 | # 1203 | elif [[ "${1}" == "" ]]; then 1204 | # TODO Do we need a flag to print BASE_STMT_INDENT when included? 1205 | # 1206 | printf "\n" 1207 | # Line is text 1208 | # 1209 | elif [[ "${1}" =~ $STATEMENT_BLOCK_TEXT_REGEX ]]; then 1210 | print_text "${BLOCK_INDENT}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[1]}" 1211 | # Line is assumed to be a statement 1212 | # TEXT_REGEX is perfect for this, so just re-use it 1213 | # NOTE: Regex always matches 1214 | # 1215 | elif [[ "${1}" =~ $TEXT_REGEX ]]; then 1216 | print_statement "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" 1217 | fi 1218 | } 1219 | 1220 | ####################################################################### 1221 | # Main 1222 | ####################################################################### 1223 | 1224 | function version() { 1225 | printf "%s\n" "${VERSION}" 1226 | } 1227 | 1228 | ## 1229 | # parse_env_delims - Set Delims from Environment Vars 1230 | # 1231 | function parse_env_delims() { 1232 | if [ -n "${BASH_TPL_TAG_DELIMS}" ]; then 1233 | parse_tag_delims "${BASH_TPL_TAG_DELIMS}" "BASH_TPL_TAG_DELIMS" 1234 | fi 1235 | 1236 | if [ -n "${BASH_TPL_TAG_STMT_DELIM}" ]; then 1237 | parse_tag_stmt_delim "${BASH_TPL_TAG_STMT_DELIM}" "BASH_TPL_TAG_STMT_DELIM" 1238 | fi 1239 | 1240 | if [ -n "${BASH_TPL_TAG_FMT_DELIMS}" ]; then 1241 | parse_tag_fmt_delims "${BASH_TPL_TAG_FMT_DELIMS}" "BASH_TPL_TAG_FMT_DELIMS" 1242 | fi 1243 | 1244 | if [ -n "${BASH_TPL_STMT_DELIM}" ]; then 1245 | parse_stmt_delim "${BASH_TPL_STMT_DELIM}" "BASH_TPL_STMT_DELIM" 1246 | fi 1247 | 1248 | if [ -n "${BASH_TPL_STMT_BLOCK_DELIMS}" ]; then 1249 | parse_stmt_block_delims "${BASH_TPL_STMT_BLOCK_DELIMS}" "BASH_TPL_STMT_BLOCK_DELIMS" 1250 | fi 1251 | 1252 | if [ -n "${BASH_TPL_TEXT_DELIM}" ]; then 1253 | parse_text_delim "${BASH_TPL_TEXT_DELIM}" "BASH_TPL_TEXT_DELIM" 1254 | fi 1255 | 1256 | if [ -n "${BASH_TPL_DIR_DELIM}" ]; then 1257 | parse_directive_delim "${BASH_TPL_DIR_DELIM}" "BASH_TPL_DIR_DELIM" 1258 | fi 1259 | 1260 | if [ -n "${BASH_TPL_CMT_DELIM}" ]; then 1261 | parse_comment_delim "${BASH_TPL_CMT_DELIM}" "BASH_TPL_CMT_DELIM" 1262 | fi 1263 | } 1264 | 1265 | ## 1266 | # parse_args 1267 | # $@ args to parse 1268 | # 1269 | # Stores positional args in global array __ARGS[@] 1270 | # 1271 | function parse_args() { 1272 | __ARGS=() # Global 1273 | while (($#)); do 1274 | case "$1" in 1275 | -h | --help) 1276 | usage 1277 | exit 0 1278 | ;; 1279 | --version) 1280 | version 1281 | exit 0 1282 | ;; 1283 | -o | --output-file) 1284 | if [ -n "${2}" ]; then 1285 | OUTPUT_FILE="${2}" 1286 | else 1287 | echo "Error: Invalid or missing value for --output-file: '${2}'" >&2 1288 | exit 1 1289 | fi 1290 | shift 2 1291 | ;; 1292 | --reset-delims) 1293 | # Reset delims immediately - Any delim flags after this will be honored 1294 | # 1295 | reset_delims 1296 | shift 1297 | ;; 1298 | --tag-delims) 1299 | parse_tag_delims "$2" "$1" 1300 | shift 2 1301 | ;; 1302 | --tag-stmt-delim) 1303 | parse_tag_stmt_delim "$2" "$1" 1304 | shift 2 1305 | ;; 1306 | --tag-fmt-delims) 1307 | parse_tag_fmt_delims "$2" "$1" 1308 | shift 2 1309 | ;; 1310 | --stmt-delim) 1311 | parse_stmt_delim "$2" "$1" 1312 | shift 2 1313 | ;; 1314 | --stmt-block-delims) 1315 | parse_stmt_block_delims "$2" "$1" 1316 | shift 2 1317 | ;; 1318 | --txt-delim | --text-delim) 1319 | parse_text_delim "$2" "$1" 1320 | shift 2 1321 | ;; 1322 | --dir-delim | --directive-delim) 1323 | parse_directive_delim "$2" "$1" 1324 | shift 2 1325 | ;; 1326 | --cmt-delim | --comment-delim) 1327 | parse_comment_delim "$2" "$1" 1328 | shift 2 1329 | ;; 1330 | --text-indent) 1331 | BASE_TEXT_INDENT="${2}" 1332 | shift 2 1333 | ;; 1334 | --stmt-indent) 1335 | BASE_STMT_INDENT="${2}" 1336 | shift 2 1337 | ;; 1338 | --block-indent) 1339 | BASE_BLOCK_INDENT="${2}" 1340 | shift 2 1341 | ;; 1342 | --file-not-found-ok) # internal flag to support .INCLUDE? 1343 | FILE_NOT_FOUND_OK=1 1344 | shift 1345 | ;; 1346 | -) 1347 | __ARGS+=("$1") 1348 | shift 1349 | ;; 1350 | --) 1351 | shift 1352 | while (($#)); do 1353 | __ARGS+=("$1") 1354 | shift 1355 | done 1356 | ;; 1357 | --* | -*) # unsupported flags 1358 | echo "Error: unknown flag: '$1'; use -h for help" >&2 1359 | exit 1 1360 | ;; 1361 | *) # preserve positional arguments 1362 | __ARGS+=("$1") 1363 | shift 1364 | ;; 1365 | esac 1366 | done 1367 | } 1368 | 1369 | function main() { 1370 | 1371 | OUTPUT_FILE="" 1372 | 1373 | BASE_TEXT_INDENT="" 1374 | BASE_STMT_INDENT="" 1375 | BASE_BLOCK_INDENT="" 1376 | 1377 | reset_delims 1378 | parse_env_delims 1379 | 1380 | FILE_NOT_FOUND_OK="" 1381 | if [ -n "${BASH_TPL_FILE_NOT_FOUND_OK}" ]; then 1382 | FILE_NOT_FOUND_OK="1" 1383 | fi 1384 | 1385 | parse_args "$@" 1386 | set -- "${__ARGS[@]}" 1387 | unset __ARGS 1388 | 1389 | # No file argument 1390 | # 1391 | if [[ -z "${1}" ]]; then 1392 | # Nothing waiting on stdin 1393 | # 1394 | if [[ -t 0 ]]; then 1395 | usage 1396 | exit 1 1397 | fi 1398 | else 1399 | # File argument is explicitly stdin 1400 | # 1401 | if [[ "${1}" == '-' ]]; then 1402 | shift 1403 | else 1404 | # File argument points to non-existing/readable file 1405 | # 1406 | if [[ ! -r "${1}" ]]; then 1407 | if [ -z "${FILE_NOT_FOUND_OK}" ]; then 1408 | echo "File not found: '${1}'" >&2 1409 | exit 1 1410 | else 1411 | # Fail silently, no message, no error code 1412 | exit 0 1413 | fi 1414 | fi 1415 | # File argument is good, re-route it to stdin 1416 | # 1417 | exec < "${1}" 1418 | shift 1419 | fi 1420 | fi 1421 | 1422 | reset_template_regexes 1423 | 1424 | if [[ -n "${OUTPUT_FILE}" ]]; then 1425 | exec > "${OUTPUT_FILE}" 1426 | fi 1427 | 1428 | process_stdin 1429 | 1430 | return 0 # ALL OK 1431 | } 1432 | 1433 | # Only process main logic if not being sourced (ie tested) 1434 | # 1435 | (return 0 2> /dev/null) || main "$@" 1436 | -------------------------------------------------------------------------------- /test/block_indents.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "BLOCK_INDENT: Should exist and be set to '' on init" { 9 | [[ "${BLOCK_INDENT-.}" == "" ]] 10 | } 11 | 12 | @test "BLOCK_INDENTS: Should exist and be empty on init" { 13 | [[ ${#BLOCK_INDENTS[@]} -eq 0 ]] 14 | } 15 | 16 | @test "push_block_indent: Should add current BLOCK_INDENT to tail of BLOCK_INDENTS array, set BLOCK_INDENT to new value" { 17 | push_block_indent "ONE" 18 | [[ ${BLOCK_INDENT} == "ONE" ]] 19 | [[ ${#BLOCK_INDENTS[@]} -eq 1 ]] 20 | [[ "${BLOCK_INDENTS[0]}" == "" ]] 21 | 22 | push_block_indent "TWO" 23 | [[ ${BLOCK_INDENT} == "TWO" ]] 24 | [[ ${#BLOCK_INDENTS[@]} -eq 2 ]] 25 | [[ "${BLOCK_INDENTS[0]}" == "" ]] 26 | [[ "${BLOCK_INDENTS[1]}" == "ONE" ]] 27 | } 28 | 29 | @test "pop_block_indent: Should remove tail of BLOCK_INDENTS array, setting BLOCK_INDENT to removed value" { 30 | push_block_indent "ONE" 31 | push_block_indent "TWO" 32 | [[ ${BLOCK_INDENT} == "TWO" ]] 33 | [[ ${#BLOCK_INDENTS[@]} -eq 2 ]] 34 | [[ "${BLOCK_INDENTS[0]}" == "" ]] 35 | [[ "${BLOCK_INDENTS[1]}" == "ONE" ]] 36 | 37 | pop_block_indent 38 | [[ ${BLOCK_INDENT} == "ONE" ]] 39 | [[ ${#BLOCK_INDENTS[@]} -eq 1 ]] 40 | [[ "${BLOCK_INDENTS[0]}" == "" ]] 41 | 42 | pop_block_indent 43 | [[ ${BLOCK_INDENT} == "" ]] 44 | [[ ${#BLOCK_INDENTS[@]} -eq 0 ]] 45 | } 46 | 47 | @test "pop_block_indent: Should set BLOCK_INDENT to '', should not generate error when BLOCK_INDENTS array is empty" { 48 | [[ ${BLOCK_INDENT} == "" ]] 49 | [[ ${#BLOCK_INDENTS[@]} -eq 0 ]] 50 | 51 | BLOCK_INDENT="." 52 | pop_block_indent 53 | [[ ${BLOCK_INDENT} == "" ]] 54 | [[ ${#BLOCK_INDENTS[@]} -eq 0 ]] 55 | 56 | BLOCK_INDENT="." 57 | pop_block_indent 58 | [[ ${BLOCK_INDENT} == "" ]] 59 | [[ ${#BLOCK_INDENTS[@]} -eq 0 ]] 60 | } 61 | -------------------------------------------------------------------------------- /test/delim-env.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "BASH_TPL_TAG_DELIMS: Should do nothing when unset or empty" { 9 | 10 | [[ -z "${TAG_START_DELIM1}" ]] 11 | [[ -z "${TAG_START_DELIM2}" ]] 12 | [[ -z "${TAG_STOP_DELIM1}" ]] 13 | [[ -z "${TAG_STOP_DELIM2}" ]] 14 | 15 | unset BASH_TPL_TAG_DELIMS 16 | parse_env_delims 17 | 18 | [[ -z "${TAG_START_DELIM1}" ]] 19 | [[ -z "${TAG_START_DELIM2}" ]] 20 | [[ -z "${TAG_STOP_DELIM1}" ]] 21 | [[ -z "${TAG_STOP_DELIM2}" ]] 22 | 23 | BASH_TPL_TAG_DELIMS='' 24 | parse_env_delims 25 | 26 | [[ -z "${TAG_START_DELIM1}" ]] 27 | [[ -z "${TAG_START_DELIM2}" ]] 28 | [[ -z "${TAG_STOP_DELIM1}" ]] 29 | [[ -z "${TAG_STOP_DELIM2}" ]] 30 | } 31 | 32 | @test "BASH_TPL_TAG_DELIMS: Should error on invalid input" { 33 | # No middle-space 34 | # 35 | BASH_TPL_TAG_DELIMS='{{}}' 36 | run parse_env_delims 37 | [[ $status -eq 1 ]] 38 | [[ "$output" == "Error: Invalid or missing tag delimiter values for BASH_TPL_TAG_DELIMS: '{{}}'" ]] 39 | 40 | # All Spaces 41 | # 42 | BASH_TPL_TAG_DELIMS=' ' 43 | run parse_env_delims 44 | [[ $status -eq 1 ]] 45 | [[ "$output" == "Error: Invalid or missing tag delimiter values for BASH_TPL_TAG_DELIMS: ' '" ]] 46 | } 47 | 48 | @test "BASH_TPL_TAG_DELIMS: Should process valid input" { 49 | 50 | [[ -z "${TAG_START_DELIM1}" ]] 51 | [[ -z "${TAG_START_DELIM2}" ]] 52 | [[ -z "${TAG_STOP_DELIM1}" ]] 53 | [[ -z "${TAG_STOP_DELIM2}" ]] 54 | 55 | BASH_TPL_TAG_DELIMS='ab cd' 56 | parse_env_delims 57 | 58 | [[ "${TAG_START_DELIM1}" == 'a' ]] 59 | [[ "${TAG_START_DELIM2}" == 'b' ]] 60 | [[ "${TAG_STOP_DELIM1}" == 'c' ]] 61 | [[ "${TAG_STOP_DELIM2}" == 'd' ]] 62 | 63 | BASH_TPL_TAG_DELIMS='{{ }}' 64 | parse_env_delims 65 | 66 | [[ "${TAG_START_DELIM1}" == '{' ]] 67 | [[ "${TAG_START_DELIM2}" == '{' ]] 68 | [[ "${TAG_STOP_DELIM1}" == '}' ]] 69 | [[ "${TAG_STOP_DELIM2}" == '}' ]] 70 | } 71 | 72 | @test "BASH_TPL_TAG_STMT_DELIM: Should do nothing when unset or empty" { 73 | 74 | [[ -z "${TAG_STMT_DELIM}" ]] 75 | 76 | unset BASH_TPL_TAG_STMT_DELIM 77 | parse_env_delims 78 | 79 | [[ -z "${TAG_STMT_DELIM}" ]] 80 | 81 | BASH_TPL_TAG_STMT_DELIM='' 82 | parse_env_delims 83 | 84 | [[ -z "${TAG_STMT_DELIM}" ]] 85 | } 86 | 87 | @test "BASH_TPL_TAG_STMT_DELIM: Should error on invalid input" { 88 | # Too long 89 | # 90 | BASH_TPL_TAG_STMT_DELIM='%%' 91 | run parse_env_delims 92 | [[ $status -eq 1 ]] 93 | [[ "$output" == "Error: Invalid or missing tag stmt delimiter value for BASH_TPL_TAG_STMT_DELIM: '%%'" ]] 94 | 95 | # Space 96 | # 97 | BASH_TPL_TAG_STMT_DELIM=' ' 98 | run parse_env_delims 99 | [[ $status -eq 1 ]] 100 | [[ "$output" == "Error: Invalid or missing tag stmt delimiter value for BASH_TPL_TAG_STMT_DELIM: ' '" ]] 101 | } 102 | 103 | @test "BASH_TPL_TAG_STMT_DELIM: Should process valid input" { 104 | 105 | [[ -z "${TAG_STMT_DELIM}" ]] 106 | 107 | BASH_TPL_TAG_STMT_DELIM='%' 108 | parse_env_delims 109 | 110 | [[ "${TAG_STMT_DELIM}" == '%' ]] 111 | 112 | BASH_TPL_TAG_STMT_DELIM='$' 113 | parse_env_delims 114 | 115 | [[ "${TAG_STMT_DELIM}" == '$' ]] 116 | } 117 | 118 | @test "BASH_TPL_TAG_FMT_DELIMS: Should do nothing when unset or empty" { 119 | 120 | [[ -z "${TAG_FMT_START_DELIM}" ]] 121 | [[ -z "${TAG_FMT_STOP_DELIM}" ]] 122 | 123 | unset BASH_TPL_TAG_FMT_DELIMS 124 | parse_env_delims 125 | 126 | [[ -z "${TAG_FMT_START_DELIM}" ]] 127 | [[ -z "${TAG_FMT_STOP_DELIM}" ]] 128 | 129 | BASH_TPL_TAG_FMT_DELIMS='' 130 | parse_env_delims 131 | 132 | [[ -z "${TAG_FMT_START_DELIM}" ]] 133 | [[ -z "${TAG_FMT_STOP_DELIM}" ]] 134 | } 135 | 136 | @test "BASH_TPL_TAG_FMT_DELIMS: Should error on invalid input" { 137 | # No middle-space 138 | # 139 | BASH_TPL_TAG_FMT_DELIMS='||' 140 | run parse_env_delims 141 | [[ $status -eq 1 ]] 142 | [[ "$output" == "Error: Invalid or missing tag fmt delimiter values for BASH_TPL_TAG_FMT_DELIMS: '||'" ]] 143 | 144 | # All Spaces 145 | # 146 | BASH_TPL_TAG_FMT_DELIMS=' ' 147 | run parse_env_delims 148 | [[ $status -eq 1 ]] 149 | [[ "$output" == "Error: Invalid or missing tag fmt delimiter values for BASH_TPL_TAG_FMT_DELIMS: ' '" ]] 150 | } 151 | 152 | @test "BASH_TPL_TAG_FMT_DELIMS: Should process valid input" { 153 | 154 | [[ -z "${TAG_FMT_START_DELIM}" ]] 155 | [[ -z "${TAG_FMT_STOP_DELIM}" ]] 156 | 157 | BASH_TPL_TAG_FMT_DELIMS='a b' 158 | parse_env_delims 159 | 160 | [[ "${TAG_FMT_START_DELIM}" == 'a' ]] 161 | [[ "${TAG_FMT_STOP_DELIM}" == 'b' ]] 162 | 163 | BASH_TPL_TAG_FMT_DELIMS='[ ]' 164 | parse_env_delims 165 | 166 | [[ "${TAG_FMT_START_DELIM}" == '[' ]] 167 | [[ "${TAG_FMT_STOP_DELIM}" == ']' ]] 168 | } 169 | 170 | @test "BASH_TPL_STMT_DELIM: Should do nothing when unset or empty" { 171 | 172 | [[ -z "${STMT_DELIM}" ]] 173 | 174 | unset BASH_TPL_STMT_DELIM 175 | parse_env_delims 176 | 177 | [[ -z "${STMT_DELIM}" ]] 178 | 179 | BASH_TPL_STMT_DELIM='' 180 | parse_env_delims 181 | 182 | [[ -z "${STMT_DELIM}" ]] 183 | } 184 | 185 | @test "BASH_TPL_STMT_DELIM: Should error on invalid input" { 186 | # Space 187 | # 188 | BASH_TPL_STMT_DELIM=' ' 189 | run parse_env_delims 190 | [[ $status -eq 1 ]] 191 | [[ "$output" == "Error: Invalid or missing stmt delimiter value for BASH_TPL_STMT_DELIM: ' '" ]] 192 | } 193 | 194 | @test "BASH_TPL_STMT_DELIM: Should process valid input" { 195 | 196 | [[ -z "${STMT_DELIM}" ]] 197 | 198 | BASH_TPL_STMT_DELIM='%' 199 | parse_env_delims 200 | 201 | [[ "${STMT_DELIM}" == '%' ]] 202 | 203 | BASH_TPL_STMT_DELIM='-->' 204 | parse_env_delims 205 | 206 | [[ "${STMT_DELIM}" == '-->' ]] 207 | } 208 | 209 | @test "BASH_TPL_STMT_BLOCK_DELIMS: Should do nothing when unset or empty" { 210 | 211 | [[ -z "${STMT_BLOCK_START_DELIM}" ]] 212 | [[ -z "${STMT_BLOCK_STOP_DELIM}" ]] 213 | [[ -z "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 214 | 215 | STMT_BLOCK_DELIM_UNDEFINED=1 216 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 217 | 218 | unset BASH_TPL_STMT_BLOCK_DELIMS 219 | parse_env_delims 220 | 221 | [[ -z "${STMT_BLOCK_START_DELIM}" ]] 222 | [[ -z "${STMT_BLOCK_STOP_DELIM}" ]] 223 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 224 | 225 | BASH_TPL_STMT_BLOCK_DELIMS='' 226 | parse_env_delims 227 | 228 | [[ -z "${STMT_BLOCK_START_DELIM}" ]] 229 | [[ -z "${STMT_BLOCK_STOP_DELIM}" ]] 230 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 231 | } 232 | 233 | @test "BASH_TPL_STMT_BLOCK_DELIMS: Should error on invalid input" { 234 | # All Spaces 235 | # 236 | BASH_TPL_STMT_BLOCK_DELIMS=' ' 237 | run parse_env_delims 238 | [[ $status -eq 1 ]] 239 | [[ "$output" == "Error: Invalid or missing stmt-block delimiter values for BASH_TPL_STMT_BLOCK_DELIMS: ' '" ]] 240 | 241 | # No middle-space 242 | # 243 | BASH_TPL_STMT_BLOCK_DELIMS='<%%>' 244 | run parse_env_delims 245 | [[ $status -eq 1 ]] 246 | [[ "$output" == "Error: Invalid or missing stmt-block delimiter values for BASH_TPL_STMT_BLOCK_DELIMS: '<%%>'" ]] 247 | } 248 | 249 | @test "BASH_TPL_STMT_BLOCK_DELIMS: Should process valid input" { 250 | 251 | [[ -z "${STMT_BLOCK_START_DELIM}" ]] 252 | [[ -z "${STMT_BLOCK_STOP_DELIM}" ]] 253 | [[ -z "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 254 | 255 | STMT_BLOCK_DELIM_UNDEFINED=1 256 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 257 | 258 | BASH_TPL_STMT_BLOCK_DELIMS='ab cd' 259 | parse_env_delims 260 | 261 | [[ "${STMT_BLOCK_START_DELIM}" == 'ab' ]] 262 | [[ "${STMT_BLOCK_STOP_DELIM}" == 'cd' ]] 263 | [[ -z "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 264 | 265 | STMT_BLOCK_DELIM_UNDEFINED=1 266 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 267 | 268 | BASH_TPL_STMT_BLOCK_DELIMS='<% %>' 269 | parse_env_delims 270 | 271 | [[ "${STMT_BLOCK_START_DELIM}" == '<%' ]] 272 | [[ "${STMT_BLOCK_STOP_DELIM}" == '%>' ]] 273 | [[ -z "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 274 | } 275 | 276 | @test "BASH_TPL_TEXT_DELIM: Should do nothing when unset or empty" { 277 | 278 | [[ -z "${TEXT_DELIM}" ]] 279 | [[ -z "${TEXT_DELIM_UNDEFINED}" ]] 280 | 281 | TEXT_DELIM_UNDEFINED=1 282 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 283 | 284 | unset BASH_TPL_TEXT_DELIM 285 | parse_env_delims 286 | 287 | [[ -z "${TEXT_DELIM}" ]] 288 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 289 | 290 | BASH_TPL_TEXT_DELIM='' 291 | parse_env_delims 292 | 293 | [[ -z "${TEXT_DELIM}" ]] 294 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 295 | } 296 | 297 | @test "BASH_TPL_TEXT_DELIM: Should error on invalid input" { 298 | # Space 299 | # 300 | BASH_TPL_TEXT_DELIM=' ' 301 | run parse_env_delims 302 | [[ $status -eq 1 ]] 303 | [[ "$output" == "Error: Invalid or missing text delimiter value for BASH_TPL_TEXT_DELIM: ' '" ]] 304 | } 305 | 306 | @test "BASH_TPL_TEXT_DELIM: Should process valid input" { 307 | 308 | [[ -z "${TEXT_DELIM}" ]] 309 | [[ -z "${TEXT_DELIM_UNDEFINED}" ]] 310 | 311 | TEXT_DELIM_UNDEFINED=1 312 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 313 | 314 | BASH_TPL_TEXT_DELIM='% ' 315 | parse_env_delims 316 | 317 | [[ "${TEXT_DELIM}" == '% ' ]] 318 | [[ -z "${TEXT_DELIM_UNDEFINED}" ]] 319 | 320 | TEXT_DELIM_UNDEFINED=1 321 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 322 | 323 | BASH_TPL_TEXT_DELIM='>>' 324 | parse_env_delims 325 | 326 | [[ "${TEXT_DELIM}" == '>>' ]] 327 | [[ -z "${TEXT_DELIM_UNDEFINED}" ]] 328 | } 329 | 330 | @test "BASH_TPL_DIR_DELIM: Should do nothing when unset or empty" { 331 | 332 | [[ -z "${DIRECTIVE_DELIM}" ]] 333 | 334 | unset BASH_TPL_DIR_DELIM 335 | parse_env_delims 336 | 337 | [[ -z "${DIRECTIVE_DELIM}" ]] 338 | 339 | BASH_TPL_DIR_DELIM='' 340 | parse_env_delims 341 | 342 | [[ -z "${DIRECTIVE_DELIM}" ]] 343 | } 344 | 345 | @test "BASH_TPL_DIR_DELIM: Should error on invalid input" { 346 | # Space 347 | # 348 | BASH_TPL_DIR_DELIM=' ' 349 | run parse_env_delims 350 | [[ $status -eq 1 ]] 351 | [[ "$output" == "Error: Invalid or missing directive delimiter value for BASH_TPL_DIR_DELIM: ' '" ]] 352 | } 353 | 354 | @test "BASH_TPL_DIR_DELIM: Should process valid input" { 355 | 356 | [[ -z "${DIRECTIVE_DELIM}" ]] 357 | 358 | BASH_TPL_DIR_DELIM='.' 359 | parse_env_delims 360 | 361 | [[ "${DIRECTIVE_DELIM}" == '.' ]] 362 | 363 | BASH_TPL_DIR_DELIM='-->' 364 | parse_env_delims 365 | 366 | [[ "${DIRECTIVE_DELIM}" == '-->' ]] 367 | } 368 | 369 | @test "BASH_TPL_CMT_DELIM: Should do nothing when unset or empty" { 370 | 371 | [[ -z "${COMMENT_DELIM}" ]] 372 | [[ -z "${COMMENT_DELIM_UNDEFINED}" ]] 373 | 374 | COMMENT_DELIM_UNDEFINED=1 375 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 376 | 377 | unset BASH_TPL_CMT_DELIM 378 | parse_env_delims 379 | 380 | [[ -z "${COMMENT_DELIM}" ]] 381 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 382 | 383 | BASH_TPL_CMT_DELIM='' 384 | parse_env_delims 385 | 386 | [[ -z "${COMMENT_DELIM}" ]] 387 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 388 | } 389 | 390 | @test "BASH_TPL_CMT_DELIM: Should error on invalid input" { 391 | # Space 392 | # 393 | BASH_TPL_CMT_DELIM=' ' 394 | run parse_env_delims 395 | [[ $status -eq 1 ]] 396 | [[ "$output" == "Error: Invalid or missing comment delimiter value for BASH_TPL_CMT_DELIM: ' '" ]] 397 | } 398 | 399 | @test "BASH_TPL_CMT_DELIM: Should process valid input" { 400 | 401 | [[ -z "${COMMENT_DELIM}" ]] 402 | [[ -z "${COMMENT_DELIM_UNDEFINED}" ]] 403 | 404 | COMMENT_DELIM_UNDEFINED=1 405 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 406 | 407 | BASH_TPL_CMT_DELIM='#' 408 | parse_env_delims 409 | 410 | [[ "${COMMENT_DELIM}" == '#' ]] 411 | [[ -z "${COMMENT_DELIM_UNDEFINED}" ]] 412 | 413 | COMMENT_DELIM_UNDEFINED=1 414 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 415 | 416 | BASH_TPL_CMT_DELIM='//' 417 | parse_env_delims 418 | 419 | [[ "${COMMENT_DELIM}" == '//' ]] 420 | [[ -z "${COMMENT_DELIM_UNDEFINED}" ]] 421 | } 422 | -------------------------------------------------------------------------------- /test/delim-functions.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "reset_delims: should set default delims" { 9 | 10 | reset_delims 11 | 12 | [[ "${TAG_START_DELIM1}" == '<' ]] 13 | [[ "${TAG_START_DELIM2}" == '%' ]] 14 | [[ "${TAG_STOP_DELIM1}" == '%' ]] 15 | [[ "${TAG_STOP_DELIM2}" == '>' ]] 16 | [[ "${TAG_STMT_DELIM}" == '%' ]] 17 | [[ "${TAG_FMT_START_DELIM}" == '|' ]] 18 | [[ "${TAG_FMT_STOP_DELIM}" == '|' ]] 19 | [[ "${STMT_DELIM}" == '%' ]] 20 | [[ "${STMT_BLOCK_DELIM_UNDEFINED}" == '1' ]] 21 | [[ "${STMT_BLOCK_START_DELIM}" == '' ]] 22 | [[ "${STMT_BLOCK_STOP_DELIM}" == '' ]] 23 | [[ "${TEXT_DELIM_UNDEFINED}" == '1' ]] 24 | [[ "${TEXT_DELIM}" == '' ]] 25 | [[ "${DIRECTIVE_DELIM}" == '.' ]] 26 | [[ "${COMMENT_DELIM_UNDEFINED}" == '1' ]] 27 | [[ "${COMMENT_DELIM}" == '' ]] 28 | } 29 | 30 | @test "parse_tag_delims: Should error on invalid input" { 31 | # Empty 32 | # 33 | run parse_tag_delims '' 'BATS' 34 | [[ $status -eq 1 ]] 35 | [[ "$output" == "Error: Invalid or missing tag delimiter values for BATS: ''" ]] 36 | 37 | # All Spaces 38 | # 39 | run parse_tag_delims ' ' 'BATS' 40 | [[ $status -eq 1 ]] 41 | [[ "$output" == "Error: Invalid or missing tag delimiter values for BATS: ' '" ]] 42 | 43 | # No middle-space 44 | # 45 | run parse_tag_delims '{{}}' 'BATS' 46 | [[ $status -eq 1 ]] 47 | [[ "$output" == "Error: Invalid or missing tag delimiter values for BATS: '{{}}'" ]] 48 | } 49 | 50 | @test "parse_tag_delims: Should process valid input" { 51 | 52 | [[ -z "${TAG_START_DELIM1}" ]] 53 | [[ -z "${TAG_START_DELIM2}" ]] 54 | [[ -z "${TAG_STOP_DELIM1}" ]] 55 | [[ -z "${TAG_STOP_DELIM2}" ]] 56 | 57 | parse_tag_delims 'ab cd' 58 | 59 | [[ "${TAG_START_DELIM1}" == 'a' ]] 60 | [[ "${TAG_START_DELIM2}" == 'b' ]] 61 | [[ "${TAG_STOP_DELIM1}" == 'c' ]] 62 | [[ "${TAG_STOP_DELIM2}" == 'd' ]] 63 | 64 | parse_tag_delims '{{ }}' 65 | 66 | [[ "${TAG_START_DELIM1}" == '{' ]] 67 | [[ "${TAG_START_DELIM2}" == '{' ]] 68 | [[ "${TAG_STOP_DELIM1}" == '}' ]] 69 | [[ "${TAG_STOP_DELIM2}" == '}' ]] 70 | } 71 | 72 | @test "parse_tag_stmt_delim: Should error on invalid input" { 73 | # Empty 74 | # 75 | run parse_tag_stmt_delim '' 'BATS' 76 | [[ $status -eq 1 ]] 77 | [[ "$output" == "Error: Invalid or missing tag stmt delimiter value for BATS: ''" ]] 78 | 79 | # Space 80 | # 81 | run parse_tag_stmt_delim ' ' 'BATS' 82 | [[ $status -eq 1 ]] 83 | [[ "$output" == "Error: Invalid or missing tag stmt delimiter value for BATS: ' '" ]] 84 | 85 | # Too long 86 | # 87 | run parse_tag_stmt_delim '%%' 'BATS' 88 | [[ $status -eq 1 ]] 89 | [[ "$output" == "Error: Invalid or missing tag stmt delimiter value for BATS: '%%'" ]] 90 | } 91 | 92 | @test "parse_tag_stmt_delim: Should process valid input" { 93 | 94 | [[ -z "${TAG_STMT_DELIM}" ]] 95 | 96 | parse_tag_stmt_delim '%' 97 | 98 | [[ "${TAG_STMT_DELIM}" == '%' ]] 99 | 100 | parse_tag_stmt_delim '$' 101 | 102 | [[ "${TAG_STMT_DELIM}" == '$' ]] 103 | } 104 | 105 | @test "parse_tag_fmt_delims: Should error on invalid input" { 106 | # Empty 107 | # 108 | run parse_tag_fmt_delims '' 'BATS' 109 | [[ $status -eq 1 ]] 110 | [[ "$output" == "Error: Invalid or missing tag fmt delimiter values for BATS: ''" ]] 111 | 112 | # All Spaces 113 | # 114 | run parse_tag_fmt_delims ' ' 'BATS' 115 | [[ $status -eq 1 ]] 116 | [[ "$output" == "Error: Invalid or missing tag fmt delimiter values for BATS: ' '" ]] 117 | 118 | # No middle-space 119 | # 120 | run parse_tag_fmt_delims '||' 'BATS' 121 | [[ $status -eq 1 ]] 122 | [[ "$output" == "Error: Invalid or missing tag fmt delimiter values for BATS: '||'" ]] 123 | } 124 | 125 | @test "parse_tag_fmt_delims: Should process valid input" { 126 | 127 | [[ -z "${TAG_FMT_START_DELIM}" ]] 128 | [[ -z "${TAG_FMT_STOP_DELIM}" ]] 129 | 130 | parse_tag_fmt_delims '| |' 131 | 132 | [[ "${TAG_FMT_START_DELIM}" == '|' ]] 133 | [[ "${TAG_FMT_STOP_DELIM}" == '|' ]] 134 | 135 | parse_tag_fmt_delims '[ ]' 136 | 137 | [[ "${TAG_FMT_START_DELIM}" == '[' ]] 138 | [[ "${TAG_FMT_STOP_DELIM}" == ']' ]] 139 | } 140 | 141 | @test "parse_stmt_delim: Should error on invalid input" { 142 | # Empty 143 | # 144 | run parse_stmt_delim '' 'BATS' 145 | [[ $status -eq 1 ]] 146 | [[ "$output" == "Error: Invalid or missing stmt delimiter value for BATS: ''" ]] 147 | 148 | # Space 149 | # 150 | run parse_stmt_delim ' ' 'BATS' 151 | [[ $status -eq 1 ]] 152 | [[ "$output" == "Error: Invalid or missing stmt delimiter value for BATS: ' '" ]] 153 | } 154 | 155 | @test "parse_stmt_delim: Should process valid input" { 156 | 157 | [[ -z "${STMT_DELIM}" ]] 158 | 159 | parse_stmt_delim '%' 160 | 161 | [[ "${STMT_DELIM}" == '%' ]] 162 | 163 | parse_stmt_delim '-->' 164 | 165 | [[ "${STMT_DELIM}" == '-->' ]] 166 | } 167 | 168 | @test "parse_stmt_block_delims: Should error on invalid input" { 169 | # Empty 170 | # 171 | run parse_stmt_block_delims '' 'BATS' 172 | [[ $status -eq 1 ]] 173 | [[ "$output" == "Error: Invalid or missing stmt-block delimiter values for BATS: ''" ]] 174 | 175 | # All Spaces 176 | # 177 | run parse_stmt_block_delims ' ' 'BATS' 178 | [[ $status -eq 1 ]] 179 | [[ "$output" == "Error: Invalid or missing stmt-block delimiter values for BATS: ' '" ]] 180 | 181 | # No middle-space 182 | # 183 | run parse_stmt_block_delims '<%%>' 'BATS' 184 | [[ $status -eq 1 ]] 185 | [[ "$output" == "Error: Invalid or missing stmt-block delimiter values for BATS: '<%%>'" ]] 186 | } 187 | 188 | @test "parse_stmt_block_delims: Should process valid input" { 189 | 190 | [[ -z "${STMT_BLOCK_START_DELIM}" ]] 191 | [[ -z "${STMT_BLOCK_STOP_DELIM}" ]] 192 | [[ -z "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 193 | 194 | STMT_BLOCK_DELIM_UNDEFINED=1 195 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 196 | parse_stmt_block_delims 'ab cd' 197 | 198 | [[ "${STMT_BLOCK_START_DELIM}" == 'ab' ]] 199 | [[ "${STMT_BLOCK_STOP_DELIM}" == 'cd' ]] 200 | [[ -z "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 201 | 202 | STMT_BLOCK_DELIM_UNDEFINED=1 203 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 204 | parse_stmt_block_delims '<% %>' 205 | 206 | [[ "${STMT_BLOCK_START_DELIM}" == '<%' ]] 207 | [[ "${STMT_BLOCK_STOP_DELIM}" == '%>' ]] 208 | [[ -z "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 209 | } 210 | 211 | @test "parse_directive_delim: Should error on invalid input" { 212 | # Empty 213 | # 214 | run parse_directive_delim '' 'BATS' 215 | [[ $status -eq 1 ]] 216 | [[ "$output" == "Error: Invalid or missing directive delimiter value for BATS: ''" ]] 217 | 218 | # Space 219 | # 220 | run parse_directive_delim ' ' 'BATS' 221 | [[ $status -eq 1 ]] 222 | [[ "$output" == "Error: Invalid or missing directive delimiter value for BATS: ' '" ]] 223 | } 224 | 225 | @test "parse_text_delim: Should error on invalid input" { 226 | # Empty 227 | # 228 | run parse_text_delim '' 'BATS' 229 | [[ $status -eq 1 ]] 230 | [[ "$output" == "Error: Invalid or missing text delimiter value for BATS: ''" ]] 231 | 232 | # Space 233 | # 234 | run parse_text_delim ' ' 'BATS' 235 | [[ $status -eq 1 ]] 236 | [[ "$output" == "Error: Invalid or missing text delimiter value for BATS: ' '" ]] 237 | } 238 | 239 | @test "parse_text_delim: Should process valid input" { 240 | 241 | [[ -z "${TEXT_DELIM}" ]] 242 | [[ -z "${TEXT_DELIM_UNDEFINED}" ]] 243 | 244 | TEXT_DELIM_UNDEFINED=1 245 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 246 | parse_text_delim '% ' 247 | 248 | [[ "${TEXT_DELIM}" == '% ' ]] 249 | [[ -z "${TEXT_DELIM_UNDEFINED}" ]] 250 | 251 | TEXT_DELIM_UNDEFINED=1 252 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 253 | parse_text_delim '>>' 254 | 255 | [[ "${TEXT_DELIM}" == '>>' ]] 256 | [[ -z "${TEXT_DELIM_UNDEFINED}" ]] 257 | } 258 | 259 | @test "parse_directive_delim: Should process valid input" { 260 | 261 | [[ -z "${DIRECTIVE_DELIM}" ]] 262 | 263 | parse_directive_delim '.' 264 | 265 | [[ "${DIRECTIVE_DELIM}" == '.' ]] 266 | 267 | parse_directive_delim '-->' 268 | 269 | [[ "${DIRECTIVE_DELIM}" == '-->' ]] 270 | } 271 | 272 | @test "parse_comment_delim: Should error on invalid input" { 273 | # Empty 274 | # 275 | run parse_comment_delim '' 'BATS' 276 | [[ $status -eq 1 ]] 277 | [[ "$output" == "Error: Invalid or missing comment delimiter value for BATS: ''" ]] 278 | 279 | # Space 280 | # 281 | run parse_comment_delim ' ' 'BATS' 282 | [[ $status -eq 1 ]] 283 | [[ "$output" == "Error: Invalid or missing comment delimiter value for BATS: ' '" ]] 284 | } 285 | 286 | @test "parse_comment_delim: Should process valid input" { 287 | 288 | [[ -z "${COMMENT_DELIM}" ]] 289 | [[ -z "${COMMENT_DELIM_UNDEFINED}" ]] 290 | 291 | COMMENT_DELIM_UNDEFINED=1 292 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 293 | parse_comment_delim '#' 294 | 295 | [[ "${COMMENT_DELIM}" == '#' ]] 296 | [[ -z "${COMMENT_DELIM_UNDEFINED}" ]] 297 | 298 | COMMENT_DELIM_UNDEFINED=1 299 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 300 | parse_comment_delim '//' 301 | 302 | [[ "${COMMENT_DELIM}" == '//' ]] 303 | [[ -z "${COMMENT_DELIM_UNDEFINED}" ]] 304 | } 305 | -------------------------------------------------------------------------------- /test/delim-regexes.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "delim regexes should be defined" { 9 | [[ -n "${TAG_DELIM_REGEX}" ]] 10 | [[ -n "${TAG_STMT_DELIM_REGEX}" ]] 11 | [[ -n "${TAG_FMT_DELIM_REGEX}" ]] 12 | [[ -n "${STMT_DELIM_REGEX}" ]] 13 | [[ -n "${STMT_BLOCK_DELIM_REGEX}" ]] 14 | [[ -n "${STMT_BLOCK_TEXT_REGEX}" ]] 15 | } 16 | 17 | @test "TAG_DELIM_REGEX: invalid data should fail" { 18 | [[ ! '' =~ $TAG_DELIM_REGEX ]] 19 | [[ ! ' ' =~ $TAG_DELIM_REGEX ]] 20 | [[ ! 'a b' =~ $TAG_DELIM_REGEX ]] 21 | [[ ! 'a bc' =~ $TAG_DELIM_REGEX ]] 22 | [[ ! 'a bcd' =~ $TAG_DELIM_REGEX ]] 23 | [[ ! 'ab c' =~ $TAG_DELIM_REGEX ]] 24 | [[ ! 'ab cde' =~ $TAG_DELIM_REGEX ]] 25 | [[ ! 'abc def' =~ $TAG_DELIM_REGEX ]] 26 | [[ ! 'abcd' =~ $TAG_DELIM_REGEX ]] 27 | [[ ! ' ab cd' =~ $TAG_DELIM_REGEX ]] 28 | [[ ! 'ab cd ' =~ $TAG_DELIM_REGEX ]] 29 | [[ ! ' ab cd ' =~ $TAG_DELIM_REGEX ]] 30 | [[ ! 'ab cd' =~ $TAG_DELIM_REGEX ]] 31 | } 32 | 33 | @test "TAG_DELIM_REGEX: valid data should pass" { 34 | [[ 'ab cd' =~ $TAG_DELIM_REGEX ]] 35 | [[ "${BASH_REMATCH[1]}" == 'a' ]] 36 | [[ "${BASH_REMATCH[2]}" == 'b' ]] 37 | [[ "${BASH_REMATCH[3]}" == 'c' ]] 38 | [[ "${BASH_REMATCH[4]}" == 'd' ]] 39 | 40 | [[ '{{ }}' =~ $TAG_DELIM_REGEX ]] 41 | [[ "${BASH_REMATCH[1]}" == '{' ]] 42 | [[ "${BASH_REMATCH[2]}" == '{' ]] 43 | [[ "${BASH_REMATCH[3]}" == '}' ]] 44 | [[ "${BASH_REMATCH[4]}" == '}' ]] 45 | 46 | [[ '<% %>' =~ $TAG_DELIM_REGEX ]] 47 | [[ "${BASH_REMATCH[1]}" == '<' ]] 48 | [[ "${BASH_REMATCH[2]}" == '%' ]] 49 | [[ "${BASH_REMATCH[3]}" == '%' ]] 50 | [[ "${BASH_REMATCH[4]}" == '>' ]] 51 | 52 | [[ '.. ..' =~ $TAG_DELIM_REGEX ]] 53 | [[ "${BASH_REMATCH[1]}" == '.' ]] 54 | [[ "${BASH_REMATCH[2]}" == '.' ]] 55 | [[ "${BASH_REMATCH[3]}" == '.' ]] 56 | [[ "${BASH_REMATCH[4]}" == '.' ]] 57 | } 58 | 59 | @test "TAG_STMT_DELIM_REGEX: invalid data should fail" { 60 | [[ ! '' =~ $TAG_STMT_DELIM_REGEX ]] 61 | [[ ! ' ' =~ $TAG_STMT_DELIM_REGEX ]] 62 | [[ ! ' a' =~ $TAG_STMT_DELIM_REGEX ]] 63 | [[ ! 'a ' =~ $TAG_STMT_DELIM_REGEX ]] 64 | [[ ! 'ab' =~ $TAG_STMT_DELIM_REGEX ]] 65 | [[ ! 'a b' =~ $TAG_STMT_DELIM_REGEX ]] 66 | [[ ! 'abc' =~ $TAG_STMT_DELIM_REGEX ]] 67 | } 68 | 69 | @test "TAG_STMT_DELIM_REGEX: valid data should pass" { 70 | [[ 'a' =~ $TAG_STMT_DELIM_REGEX ]] 71 | [[ "${BASH_REMATCH[1]}" == 'a' ]] 72 | 73 | [[ '%' =~ $TAG_STMT_DELIM_REGEX ]] 74 | [[ "${BASH_REMATCH[1]}" == '%' ]] 75 | 76 | [[ '$' =~ $TAG_STMT_DELIM_REGEX ]] 77 | [[ "${BASH_REMATCH[1]}" == '$' ]] 78 | 79 | [[ '.' =~ $TAG_STMT_DELIM_REGEX ]] 80 | [[ "${BASH_REMATCH[1]}" == '.' ]] 81 | } 82 | 83 | @test "TAG_FMT_DELIM_REGEX: invalid data should fail" { 84 | [[ ! '' =~ $TAG_FMT_DELIM_REGEX ]] 85 | [[ ! ' ' =~ $TAG_FMT_DELIM_REGEX ]] 86 | [[ ! 'a' =~ $TAG_FMT_DELIM_REGEX ]] 87 | [[ ! ' ' =~ $TAG_FMT_DELIM_REGEX ]] 88 | [[ ! 'a ' =~ $TAG_FMT_DELIM_REGEX ]] 89 | [[ ! ' b' =~ $TAG_FMT_DELIM_REGEX ]] 90 | [[ ! 'ab' =~ $TAG_FMT_DELIM_REGEX ]] 91 | [[ ! ' ' =~ $TAG_FMT_DELIM_REGEX ]] 92 | [[ ! 'a ' =~ $TAG_FMT_DELIM_REGEX ]] 93 | [[ ! ' . ' =~ $TAG_FMT_DELIM_REGEX ]] 94 | [[ ! ' b' =~ $TAG_FMT_DELIM_REGEX ]] 95 | [[ ! 'a. ' =~ $TAG_FMT_DELIM_REGEX ]] 96 | [[ ! ' .b' =~ $TAG_FMT_DELIM_REGEX ]] 97 | [[ ! 'a.b' =~ $TAG_FMT_DELIM_REGEX ]] 98 | } 99 | 100 | @test "TAG_FMT_DELIM_REGEX: valid data should pass" { 101 | [[ 'a b' =~ $TAG_FMT_DELIM_REGEX ]] 102 | [[ "${BASH_REMATCH[1]}" == 'a' ]] 103 | [[ "${BASH_REMATCH[2]}" == 'b' ]] 104 | 105 | [[ '| |' =~ $TAG_FMT_DELIM_REGEX ]] 106 | [[ "${BASH_REMATCH[1]}" == '|' ]] 107 | [[ "${BASH_REMATCH[2]}" == '|' ]] 108 | 109 | [[ '[ ]' =~ $TAG_FMT_DELIM_REGEX ]] 110 | [[ "${BASH_REMATCH[1]}" == '[' ]] 111 | [[ "${BASH_REMATCH[2]}" == ']' ]] 112 | 113 | [[ '. .' =~ $TAG_FMT_DELIM_REGEX ]] 114 | [[ "${BASH_REMATCH[1]}" == '.' ]] 115 | [[ "${BASH_REMATCH[2]}" == '.' ]] 116 | } 117 | 118 | @test "STMT_DELIM_REGEX: invalid data should fail" { 119 | [[ ! '' =~ $STMT_DELIM_REGEX ]] 120 | [[ ! ' ' =~ $STMT_DELIM_REGEX ]] 121 | [[ ! ' ' =~ $STMT_DELIM_REGEX ]] 122 | [[ ! ' a' =~ $STMT_DELIM_REGEX ]] 123 | [[ ! 'a ' =~ $STMT_DELIM_REGEX ]] 124 | [[ ! 'ab ' =~ $STMT_DELIM_REGEX ]] 125 | [[ ! 'a b' =~ $STMT_DELIM_REGEX ]] 126 | [[ ! ' ab' =~ $STMT_DELIM_REGEX ]] 127 | } 128 | 129 | @test "STMT_DELIM_REGEX: valid data should pass" { 130 | [[ 'a' =~ $STMT_DELIM_REGEX ]] 131 | [[ "${BASH_REMATCH[1]}" == 'a' ]] 132 | 133 | [[ 'ab' =~ $STMT_DELIM_REGEX ]] 134 | [[ "${BASH_REMATCH[1]}" == 'ab' ]] 135 | 136 | [[ 'abc' =~ $STMT_DELIM_REGEX ]] 137 | [[ "${BASH_REMATCH[1]}" == 'abc' ]] 138 | 139 | [[ '%' =~ $STMT_DELIM_REGEX ]] 140 | [[ "${BASH_REMATCH[1]}" == '%' ]] 141 | 142 | [[ '%%' =~ $STMT_DELIM_REGEX ]] 143 | [[ "${BASH_REMATCH[1]}" == '%%' ]] 144 | 145 | [[ '%%%' =~ $STMT_DELIM_REGEX ]] 146 | [[ "${BASH_REMATCH[1]}" == '%%%' ]] 147 | 148 | [[ '.' =~ $STMT_DELIM_REGEX ]] 149 | [[ "${BASH_REMATCH[1]}" == '.' ]] 150 | 151 | [[ '.$.' =~ $STMT_DELIM_REGEX ]] 152 | [[ "${BASH_REMATCH[1]}" == '.$.' ]] 153 | } 154 | 155 | @test "STMT_BLOCK_DELIM_REGEX: invalid data should fail" { 156 | [[ ! '' =~ $STMT_BLOCK_DELIM_REGEX ]] 157 | [[ ! ' ' =~ $STMT_BLOCK_DELIM_REGEX ]] 158 | [[ ! 'abcd' =~ $STMT_BLOCK_DELIM_REGEX ]] 159 | [[ ! ' ab cd' =~ $STMT_BLOCK_DELIM_REGEX ]] 160 | [[ ! 'ab cd ' =~ $STMT_BLOCK_DELIM_REGEX ]] 161 | [[ ! ' ab cd ' =~ $STMT_BLOCK_DELIM_REGEX ]] 162 | [[ ! 'ab cd' =~ $STMT_BLOCK_DELIM_REGEX ]] 163 | } 164 | 165 | @test "STMT_BLOCK_DELIM_REGEX: valid data should pass" { 166 | [[ 'a b' =~ $STMT_BLOCK_DELIM_REGEX ]] 167 | [[ "${BASH_REMATCH[1]}" == 'a' ]] 168 | [[ "${BASH_REMATCH[2]}" == 'b' ]] 169 | 170 | [[ 'ab cd' =~ $STMT_BLOCK_DELIM_REGEX ]] 171 | [[ "${BASH_REMATCH[1]}" == 'ab' ]] 172 | [[ "${BASH_REMATCH[2]}" == 'cd' ]] 173 | 174 | [[ 'abc def' =~ $STMT_BLOCK_DELIM_REGEX ]] 175 | [[ "${BASH_REMATCH[1]}" == 'abc' ]] 176 | [[ "${BASH_REMATCH[2]}" == 'def' ]] 177 | 178 | [[ '% %' =~ $STMT_BLOCK_DELIM_REGEX ]] 179 | [[ "${BASH_REMATCH[1]}" == '%' ]] 180 | [[ "${BASH_REMATCH[2]}" == '%' ]] 181 | 182 | [[ '<% %>' =~ $STMT_BLOCK_DELIM_REGEX ]] 183 | [[ "${BASH_REMATCH[1]}" == '<%' ]] 184 | [[ "${BASH_REMATCH[2]}" == '%>' ]] 185 | 186 | [[ '. .' =~ $STMT_BLOCK_DELIM_REGEX ]] 187 | [[ "${BASH_REMATCH[1]}" == '.' ]] 188 | [[ "${BASH_REMATCH[2]}" == '.' ]] 189 | 190 | [[ '.. ..' =~ $STMT_BLOCK_DELIM_REGEX ]] 191 | [[ "${BASH_REMATCH[1]}" == '..' ]] 192 | [[ "${BASH_REMATCH[2]}" == '..' ]] 193 | } 194 | 195 | @test "STMT_BLOCK_TEXT_REGEX: invalid data should fail" { 196 | [[ ! '' =~ $STMT_BLOCK_TEXT_REGEX ]] 197 | [[ ! ' ' =~ $STMT_BLOCK_TEXT_REGEX ]] 198 | [[ ! ' ' =~ $STMT_BLOCK_TEXT_REGEX ]] 199 | [[ ! ' a' =~ $STMT_BLOCK_TEXT_REGEX ]] 200 | [[ ! 'a ' =~ $STMT_BLOCK_TEXT_REGEX ]] 201 | [[ ! 'ab ' =~ $STMT_BLOCK_TEXT_REGEX ]] 202 | [[ ! 'a b' =~ $STMT_BLOCK_TEXT_REGEX ]] 203 | [[ ! ' ab' =~ $STMT_BLOCK_TEXT_REGEX ]] 204 | } 205 | 206 | @test "STMT_BLOCK_TEXT_REGEX: valid data should pass" { 207 | [[ 'a' =~ $STMT_BLOCK_TEXT_REGEX ]] 208 | [[ "${BASH_REMATCH[1]}" == 'a' ]] 209 | 210 | [[ 'a ' =~ $STMT_BLOCK_TEXT_REGEX ]] 211 | [[ "${BASH_REMATCH[1]}" == 'a ' ]] 212 | 213 | [[ 'ab' =~ $STMT_BLOCK_TEXT_REGEX ]] 214 | [[ "${BASH_REMATCH[1]}" == 'ab' ]] 215 | 216 | [[ 'ab ' =~ $STMT_BLOCK_TEXT_REGEX ]] 217 | [[ "${BASH_REMATCH[1]}" == 'ab ' ]] 218 | 219 | [[ 'abc' =~ $STMT_BLOCK_TEXT_REGEX ]] 220 | [[ "${BASH_REMATCH[1]}" == 'abc' ]] 221 | 222 | [[ 'abc ' =~ $STMT_BLOCK_TEXT_REGEX ]] 223 | [[ "${BASH_REMATCH[1]}" == 'abc ' ]] 224 | 225 | [[ '%' =~ $STMT_BLOCK_TEXT_REGEX ]] 226 | [[ "${BASH_REMATCH[1]}" == '%' ]] 227 | 228 | [[ '% ' =~ $STMT_BLOCK_TEXT_REGEX ]] 229 | [[ "${BASH_REMATCH[1]}" == '% ' ]] 230 | 231 | [[ '%%' =~ $STMT_BLOCK_TEXT_REGEX ]] 232 | [[ "${BASH_REMATCH[1]}" == '%%' ]] 233 | 234 | [[ '%% ' =~ $STMT_BLOCK_TEXT_REGEX ]] 235 | [[ "${BASH_REMATCH[1]}" == '%% ' ]] 236 | 237 | [[ '%%%' =~ $STMT_BLOCK_TEXT_REGEX ]] 238 | [[ "${BASH_REMATCH[1]}" == '%%%' ]] 239 | 240 | [[ '%%% ' =~ $STMT_BLOCK_TEXT_REGEX ]] 241 | [[ "${BASH_REMATCH[1]}" == '%%% ' ]] 242 | 243 | [[ '.' =~ $STMT_BLOCK_TEXT_REGEX ]] 244 | [[ "${BASH_REMATCH[1]}" == '.' ]] 245 | 246 | [[ '. ' =~ $STMT_BLOCK_TEXT_REGEX ]] 247 | [[ "${BASH_REMATCH[1]}" == '. ' ]] 248 | 249 | [[ '.$.' =~ $STMT_BLOCK_TEXT_REGEX ]] 250 | [[ "${BASH_REMATCH[1]}" == '.$.' ]] 251 | 252 | [[ '.$. ' =~ $STMT_BLOCK_TEXT_REGEX ]] 253 | [[ "${BASH_REMATCH[1]}" == '.$. ' ]] 254 | } 255 | -------------------------------------------------------------------------------- /test/lib/diff.bash: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Diff Helpers 3 | # Compare values using diff to get contextual feedback on failure 4 | ############################################################################### 5 | 6 | ## 7 | # diff_output - Diffs $output against stdin 8 | # 9 | # example: 10 | # diff_output <<< "expected value" 11 | # 12 | diff_output() { 13 | diff -a -u \ 14 | --suppress-common-lines \ 15 | --strip-trailing-cr \ 16 | --label=EXPECTED - \ 17 | --label=\$output <( printf "%s\n" "${output}" ) 18 | } 19 | 20 | ## 21 | # diff_output_file - Diffs $output against specified file 22 | # $1 = file containing expected content 23 | # 24 | # example: 25 | # diff_output_file "/path/to/file" 26 | # 27 | diff_output_file() { 28 | diff -a -u \ 29 | --suppress-common-lines \ 30 | --strip-trailing-cr \ 31 | "${1}" \ 32 | --label=\$output <( printf "%s\n" "${output}" ) 33 | } 34 | 35 | ## 36 | # diff_stderr_file - Diffs $stderr against specified file 37 | # $1 = file containing expected content 38 | # 39 | # example: 40 | # diff_stderr_file "/path/to/file" 41 | # 42 | diff_stderr_file() { 43 | diff -a -u \ 44 | --suppress-common-lines \ 45 | --strip-trailing-cr \ 46 | "${1}" \ 47 | --label=\$stderr <( printf "%s\n" "${stderr}" ) 48 | } 49 | 50 | ## 51 | # diff_vars - Diffs two variables by reference 52 | # $1 = varname of actual value 53 | # $2 = varname of expected value 54 | # 55 | # example: 56 | # diff_vars actual expected 57 | # 58 | diff_vars() { 59 | diff -a -u \ 60 | --suppress-common-lines \ 61 | --strip-trailing-cr \ 62 | --label=EXPECTED <( printf "%s" "${!2}" ) \ 63 | --label=ACTUAL <( printf "%s" "${!1}" ) 64 | } 65 | 66 | ## 67 | # diff_vals - Diffs two values 68 | # $1 = actual value 69 | # $2 = expected value 70 | # 71 | # example: 72 | # diff_vals "${actual}" "expected value" 73 | # 74 | diff_vals() { 75 | diff -a -u \ 76 | --suppress-common-lines \ 77 | --strip-trailing-cr \ 78 | --label=EXPECTED <( printf "%s" "${2}" ) \ 79 | --label=ACTUAL <( printf "%s" "${1}" ) 80 | } 81 | -------------------------------------------------------------------------------- /test/misc-functions.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "misc-function: trim" { 9 | local value 10 | 11 | value="" 12 | trim value 13 | [[ "${value}" == "" ]] 14 | 15 | value=" " 16 | trim value 17 | [[ "${value}" == "" ]] 18 | 19 | value=" " 20 | trim value 21 | [[ "${value}" == "" ]] 22 | 23 | value=" . " 24 | trim value 25 | [[ "${value}" == "." ]] 26 | 27 | value=" . " 28 | trim value 29 | [[ "${value}" == "." ]] 30 | 31 | value=" . . " 32 | trim value 33 | [[ "${value}" == ". ." ]] 34 | 35 | value=" . . " 36 | trim value 37 | [[ "${value}" == ". ." ]] 38 | 39 | value=$'\t' 40 | trim value 41 | [[ "${value}" == "" ]] 42 | 43 | value=$'\t\t' 44 | trim value 45 | [[ "${value}" == "" ]] 46 | 47 | value=$'\t.\t' 48 | trim value 49 | [[ "${value}" == "." ]] 50 | 51 | value=$'\t . \t' 52 | trim value 53 | [[ "${value}" == "." ]] 54 | 55 | value=$'\t.\t.\t' 56 | trim value 57 | [[ "${value}" == $'.\t.' ]] 58 | 59 | value=$' \t. \t . \t' 60 | trim value 61 | [[ "${value}" == $'. \t .' ]] 62 | 63 | value=$'\x01' 64 | trim value 65 | [[ "${value}" == $'\x01' ]] 66 | 67 | value=$' \x7f\t' 68 | trim value 69 | [[ "${value}" == $'\x7f' ]] 70 | 71 | value=$' \x7f\t\t' 72 | trim value 73 | [[ "${value}" == $'\x7f' ]] 74 | 75 | value=$'\t \x01\t \x7f \t' 76 | trim value 77 | [[ "${value}" == $'\x01\t \x7f' ]] 78 | } 79 | 80 | @test "misc-function: escape_regex" { 81 | local value 82 | 83 | value='' 84 | escape_regex value 85 | [[ "${value}" == '' ]] 86 | 87 | value=' ' 88 | escape_regex value 89 | [[ "${value}" == ' ' ]] 90 | 91 | value=' ' 92 | escape_regex value 93 | [[ "${value}" == ' ' ]] 94 | 95 | value='abcABC123_-' 96 | escape_regex value 97 | [[ "${value}" == 'abcABC123_-' ]] 98 | 99 | value="\\\$*+.?^|()[]{}" 100 | escape_regex value 101 | [[ "${value}" == '\\\$\*\+\.\?\^\|\(\)\[\]\{\}' ]] 102 | 103 | value='{}' 104 | escape_regex value 105 | [[ "${value}" == '\{\}' ]] 106 | 107 | value=' . ' 108 | escape_regex value 109 | [[ "${value}" == ' \. ' ]] 110 | } 111 | 112 | @test "misc-function: normalize_directive" { 113 | local value 114 | 115 | value='' 116 | normalize_directive value 117 | [[ "${value}" == '' ]] 118 | 119 | value=' ' 120 | normalize_directive value 121 | [[ "${value}" == ' ' ]] 122 | 123 | value=' ' 124 | normalize_directive value 125 | [[ "${value}" == ' ' ]] 126 | 127 | value='abc_ABC-123' 128 | normalize_directive value 129 | [[ "${value}" == 'ABC-ABC-123' ]] 130 | 131 | value=' _ ' 132 | normalize_directive value 133 | [[ "${value}" == ' - ' ]] 134 | } 135 | -------------------------------------------------------------------------------- /test/statement_indents.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "STATEMENT_INDENT: Should exist and be set to '' on init" { 9 | [[ "${STATEMENT_INDENT-.}" == "" ]] 10 | } 11 | 12 | @test "STATEMENT_INDENTS: Should exist and be empty on init" { 13 | [[ ${#STATEMENT_INDENTS[@]} -eq 0 ]] 14 | } 15 | 16 | @test "push_statement_indent: Should add current STATEMENT_INDENT to tail of STATEMENT_INDENTS array, set STATEMENT_INDENT to new value" { 17 | push_statement_indent "ONE" 18 | [[ ${STATEMENT_INDENT} == "ONE" ]] 19 | [[ ${#STATEMENT_INDENTS[@]} -eq 1 ]] 20 | [[ "${STATEMENT_INDENTS[0]}" == "" ]] 21 | 22 | push_statement_indent "TWO" 23 | [[ ${STATEMENT_INDENT} == "TWO" ]] 24 | [[ ${#STATEMENT_INDENTS[@]} -eq 2 ]] 25 | [[ "${STATEMENT_INDENTS[0]}" == "" ]] 26 | [[ "${STATEMENT_INDENTS[1]}" == "ONE" ]] 27 | } 28 | 29 | @test "pop_statement_indent: Should remove tail of STATEMENT_INDENTS array, setting STATEMENT_INDENT to removed value" { 30 | push_statement_indent "ONE" 31 | push_statement_indent "TWO" 32 | [[ ${STATEMENT_INDENT} == "TWO" ]] 33 | [[ ${#STATEMENT_INDENTS[@]} -eq 2 ]] 34 | [[ "${STATEMENT_INDENTS[0]}" == "" ]] 35 | [[ "${STATEMENT_INDENTS[1]}" == "ONE" ]] 36 | 37 | pop_statement_indent 38 | [[ ${STATEMENT_INDENT} == "ONE" ]] 39 | [[ ${#STATEMENT_INDENTS[@]} -eq 1 ]] 40 | [[ "${STATEMENT_INDENTS[0]}" == "" ]] 41 | 42 | pop_statement_indent 43 | [[ ${STATEMENT_INDENT} == "" ]] 44 | [[ ${#STATEMENT_INDENTS[@]} -eq 0 ]] 45 | } 46 | 47 | @test "pop_statement_indent: Should set STATEMENT_INDENT to '', should not generate error when STATEMENT_INDENTS array is empty" { 48 | [[ ${STATEMENT_INDENT} == "" ]] 49 | [[ ${#STATEMENT_INDENTS[@]} -eq 0 ]] 50 | 51 | STATEMENT_INDENT="." 52 | pop_statement_indent 53 | [[ ${STATEMENT_INDENT} == "" ]] 54 | [[ ${#STATEMENT_INDENTS[@]} -eq 0 ]] 55 | 56 | STATEMENT_INDENT="." 57 | pop_statement_indent 58 | [[ ${STATEMENT_INDENT} == "" ]] 59 | [[ ${#STATEMENT_INDENTS[@]} -eq 0 ]] 60 | } 61 | -------------------------------------------------------------------------------- /test/states.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "STATE: Should exist and be set to 'DEFAULT' on init" { 9 | [[ "${STATE-.}" == "DEFAULT" ]] 10 | } 11 | 12 | @test "STATES: Should exist and be empty on init" { 13 | [[ ${#STATES[@]} -eq 0 ]] 14 | } 15 | 16 | @test "push_state: Should add current STATE to tail of STATES array, set STATE to new value" { 17 | push_state "ONE" 18 | [[ ${STATE} == "ONE" ]] 19 | [[ ${#STATES[@]} -eq 1 ]] 20 | [[ "${STATES[0]}" == "DEFAULT" ]] 21 | 22 | push_state "TWO" 23 | [[ ${STATE} == "TWO" ]] 24 | [[ ${#STATES[@]} -eq 2 ]] 25 | [[ "${STATES[0]}" == "DEFAULT" ]] 26 | [[ "${STATES[1]}" == "ONE" ]] 27 | } 28 | 29 | @test "pop_state: Should remove tail of STATES array, setting STATE to removed value" { 30 | push_state "ONE" 31 | push_state "TWO" 32 | [[ ${STATE} == "TWO" ]] 33 | [[ ${#STATES[@]} -eq 2 ]] 34 | [[ "${STATES[0]}" == "DEFAULT" ]] 35 | [[ "${STATES[1]}" == "ONE" ]] 36 | 37 | pop_state 38 | [[ ${STATE} == "ONE" ]] 39 | [[ ${#STATES[@]} -eq 1 ]] 40 | [[ "${STATES[0]}" == "DEFAULT" ]] 41 | 42 | pop_state 43 | [[ ${STATE} == "DEFAULT" ]] 44 | [[ ${#STATES[@]} -eq 0 ]] 45 | } 46 | 47 | @test "pop_state: Should set STATE to 'DEFAULT', should not generate error when STATES array is empty" { 48 | [[ ${STATE} == "DEFAULT" ]] 49 | [[ ${#STATES[@]} -eq 0 ]] 50 | 51 | STATE="." 52 | pop_state 53 | [[ ${STATE} == "DEFAULT" ]] 54 | [[ ${#STATES[@]} -eq 0 ]] 55 | 56 | STATE="." 57 | pop_state 58 | [[ ${STATE} == "DEFAULT" ]] 59 | [[ ${#STATES[@]} -eq 0 ]] 60 | } 61 | -------------------------------------------------------------------------------- /test/template-regexes.bats: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2016 # Variable expression in single-quotes 2 | 3 | setup() { 4 | bats_require_minimum_version 1.7.0 5 | # shellcheck source=../bash-tpl 6 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 7 | } 8 | 9 | @test "reset_template_regexes: should default stmt-block delims to stmt-delim if not set" { 10 | 11 | reset_delims 12 | 13 | # Creates valid stmt delim, empty stmt-block delims 14 | # Sets default flag for stmt-block delims 15 | # 16 | [[ -n "${STMT_DELIM}" ]] 17 | [[ -z "${STMT_BLOCK_START_DELIM}" ]] 18 | [[ -z "${STMT_BLOCK_STOP_DELIM}" ]] 19 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 20 | 21 | reset_template_regexes 22 | 23 | # Defaults stmt-block delims to stmt delim 24 | # Leaves default flag set for stmt-block delims 25 | # 26 | [[ "${STMT_BLOCK_START_DELIM}" == "${STMT_DELIM}" ]] 27 | [[ "${STMT_BLOCK_STOP_DELIM}" == "${STMT_DELIM}" ]] 28 | [[ -n "${STMT_BLOCK_DELIM_UNDEFINED}" ]] 29 | } 30 | 31 | @test "reset_template_regexes: should default text delim to stmt-delim + ' ' if not set" { 32 | 33 | reset_delims 34 | 35 | # Creates valid stmt delim, empty text delim 36 | # Sets default flag for text delim 37 | # 38 | [[ -n "${STMT_DELIM}" ]] 39 | [[ -z "${TEXT_DELIM}" ]] 40 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 41 | 42 | reset_template_regexes 43 | 44 | # Defaults text delim to stmt delim + ' ' 45 | # Leaves default flag set for text delim 46 | # 47 | [[ "${TEXT_DELIM}" == "${STMT_DELIM} " ]] 48 | [[ -n "${TEXT_DELIM_UNDEFINED}" ]] 49 | } 50 | 51 | @test "reset_template_regexes: should default comment delim to stmt-delim + '#' if not set" { 52 | 53 | reset_delims 54 | 55 | # Creates valid stmt delim, empty comment delim 56 | # Sets default flag for comment delim 57 | # 58 | [[ -n "${STMT_DELIM}" ]] 59 | [[ -z "${COMMENT_DELIM}" ]] 60 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 61 | 62 | reset_template_regexes 63 | 64 | # Defaults comment delim to stmt delim + '#' 65 | # Leaves default flag set for comment delim 66 | # 67 | [[ "${COMMENT_DELIM}" == "${STMT_DELIM}#" ]] 68 | [[ -n "${COMMENT_DELIM_UNDEFINED}" ]] 69 | } 70 | 71 | @test "reset_template_regexes: creates template regexes" { 72 | 73 | reset_delims 74 | 75 | [[ -z "${DIRECTIVE_REGEX}" ]] 76 | [[ -z "${COMMENT_REGEX}" ]] 77 | [[ -z "${STATEMENT_REGEX}" ]] 78 | [[ -z "${STATEMENT_BLOCK_START_REGEX}" ]] 79 | [[ -z "${STATEMENT_BLOCK_STOP_REGEX}" ]] 80 | [[ -z "${STATEMENT_BLOCK_TEXT_REGEX}" ]] 81 | [[ -z "${TEXT_REGEX}" ]] 82 | [[ -z "${TAG_TEXT_REGEX}" ]] 83 | [[ -z "${TAG_STD_REGEX}" ]] 84 | [[ -z "${TAG_QUOTE_REGEX}" ]] 85 | [[ -z "${TAG_STATEMENT_REGEX}" ]] 86 | 87 | [[ -z "${TAG_STD_MATCH_IDX_FMT}" ]] 88 | [[ -z "${TAG_STD_MATCH_IDX_TXT}" ]] 89 | [[ -z "${TAG_STD_MATCH_IDX_END}" ]] 90 | 91 | [[ -z "${TAG_QUOTE_MATCH_IDX_FMT}" ]] 92 | [[ -z "${TAG_QUOTE_MATCH_IDX_TXT}" ]] 93 | [[ -z "${TAG_QUOTE_MATCH_IDX_END}" ]] 94 | 95 | [[ -z "${TAG_STATEMENT_MATCH_IDX_FMT}" ]] 96 | [[ -z "${TAG_STATEMENT_MATCH_IDX_TXT}" ]] 97 | [[ -z "${TAG_STATEMENT_MATCH_IDX_END}" ]] 98 | 99 | reset_template_regexes 100 | 101 | # TODO Determine how to confirm that the value is a valid bash regex 102 | 103 | [[ -n "${DIRECTIVE_REGEX}" ]] 104 | [[ -n "${COMMENT_REGEX}" ]] 105 | [[ -n "${STATEMENT_REGEX}" ]] 106 | [[ -n "${STATEMENT_BLOCK_START_REGEX}" ]] 107 | [[ -n "${STATEMENT_BLOCK_STOP_REGEX}" ]] 108 | [[ -n "${STATEMENT_BLOCK_TEXT_REGEX}" ]] 109 | [[ -n "${TEXT_REGEX}" ]] 110 | [[ -n "${TAG_TEXT_REGEX}" ]] 111 | [[ -n "${TAG_STD_REGEX}" ]] 112 | [[ -n "${TAG_QUOTE_REGEX}" ]] 113 | [[ -n "${TAG_STATEMENT_REGEX}" ]] 114 | 115 | [[ -n "${TAG_STD_MATCH_IDX_FMT}" ]] 116 | [[ -n "${TAG_STD_MATCH_IDX_TXT}" ]] 117 | [[ -n "${TAG_STD_MATCH_IDX_END}" ]] 118 | 119 | [[ -n "${TAG_QUOTE_MATCH_IDX_FMT}" ]] 120 | [[ -n "${TAG_QUOTE_MATCH_IDX_TXT}" ]] 121 | [[ -n "${TAG_QUOTE_MATCH_IDX_END}" ]] 122 | 123 | [[ -n "${TAG_STATEMENT_MATCH_IDX_FMT}" ]] 124 | [[ -n "${TAG_STATEMENT_MATCH_IDX_TXT}" ]] 125 | [[ -n "${TAG_STATEMENT_MATCH_IDX_END}" ]] 126 | } 127 | 128 | @test "DIRECTIVE_REGEX: should fail on invalid directive line" { 129 | # 130 | # Default delim 131 | # 132 | 133 | reset_delims 134 | reset_template_regexes 135 | 136 | [[ ! "" =~ $DIRECTIVE_REGEX ]] 137 | [[ ! "DIRECTIVE" =~ $DIRECTIVE_REGEX ]] 138 | [[ ! ". DIRECTIVE" =~ $DIRECTIVE_REGEX ]] 139 | 140 | # 141 | # Custom delim 142 | # 143 | 144 | parse_directive_delim '@' 145 | reset_template_regexes 146 | 147 | [[ ! ".DIRECTIVE" =~ $DIRECTIVE_REGEX ]] 148 | } 149 | 150 | @test "DIRECTIVE_REGEX: should match on valid directive line" { 151 | # 152 | # Default delim 153 | # 154 | 155 | reset_delims 156 | reset_template_regexes 157 | 158 | [[ ".DIRECTIVE" =~ $DIRECTIVE_REGEX ]] 159 | [[ "${BASH_REMATCH[1]}" == '' ]] 160 | [[ "${BASH_REMATCH[2]}" == 'DIRECTIVE' ]] 161 | [[ "${BASH_REMATCH[3]}" == '' ]] 162 | 163 | [[ ".My_Directive" =~ $DIRECTIVE_REGEX ]] 164 | [[ "${BASH_REMATCH[1]}" == '' ]] 165 | [[ "${BASH_REMATCH[2]}" == 'My_Directive' ]] 166 | [[ "${BASH_REMATCH[3]}" == '' ]] 167 | 168 | [[ ".my-directive" =~ $DIRECTIVE_REGEX ]] 169 | [[ "${BASH_REMATCH[1]}" == '' ]] 170 | [[ "${BASH_REMATCH[2]}" == 'my-directive' ]] 171 | [[ "${BASH_REMATCH[3]}" == '' ]] 172 | 173 | [[ ".DIRECTIVE arg1 arg2 " =~ $DIRECTIVE_REGEX ]] 174 | [[ "${BASH_REMATCH[1]}" == '' ]] 175 | [[ "${BASH_REMATCH[2]}" == 'DIRECTIVE' ]] 176 | [[ "${BASH_REMATCH[3]}" == ' arg1 arg2 ' ]] 177 | 178 | [[ " .DIRECTIVE" =~ $DIRECTIVE_REGEX ]] 179 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 180 | [[ "${BASH_REMATCH[2]}" == 'DIRECTIVE' ]] 181 | [[ "${BASH_REMATCH[3]}" == '' ]] 182 | 183 | [[ " .my_directive arg = value " =~ $DIRECTIVE_REGEX ]] 184 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 185 | [[ "${BASH_REMATCH[2]}" == 'my_directive' ]] 186 | [[ "${BASH_REMATCH[3]}" == ' arg = value ' ]] 187 | 188 | # 189 | # Custom delim 190 | # 191 | 192 | parse_directive_delim '@@' 193 | reset_template_regexes 194 | 195 | [[ "@@DIRECTIVE" =~ $DIRECTIVE_REGEX ]] 196 | [[ "${BASH_REMATCH[1]}" == '' ]] 197 | [[ "${BASH_REMATCH[2]}" == 'DIRECTIVE' ]] 198 | [[ "${BASH_REMATCH[3]}" == '' ]] 199 | 200 | [[ "@@My_Directive" =~ $DIRECTIVE_REGEX ]] 201 | [[ "${BASH_REMATCH[1]}" == '' ]] 202 | [[ "${BASH_REMATCH[2]}" == 'My_Directive' ]] 203 | [[ "${BASH_REMATCH[3]}" == '' ]] 204 | 205 | [[ "@@my-directive" =~ $DIRECTIVE_REGEX ]] 206 | [[ "${BASH_REMATCH[1]}" == '' ]] 207 | [[ "${BASH_REMATCH[2]}" == 'my-directive' ]] 208 | [[ "${BASH_REMATCH[3]}" == '' ]] 209 | 210 | [[ "@@DIRECTIVE arg1 arg2 " =~ $DIRECTIVE_REGEX ]] 211 | [[ "${BASH_REMATCH[1]}" == '' ]] 212 | [[ "${BASH_REMATCH[2]}" == 'DIRECTIVE' ]] 213 | [[ "${BASH_REMATCH[3]}" == ' arg1 arg2 ' ]] 214 | 215 | [[ " @@DIRECTIVE" =~ $DIRECTIVE_REGEX ]] 216 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 217 | [[ "${BASH_REMATCH[2]}" == 'DIRECTIVE' ]] 218 | [[ "${BASH_REMATCH[3]}" == '' ]] 219 | 220 | [[ " @@my_directive arg = value " =~ $DIRECTIVE_REGEX ]] 221 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 222 | [[ "${BASH_REMATCH[2]}" == 'my_directive' ]] 223 | [[ "${BASH_REMATCH[3]}" == ' arg = value ' ]] 224 | } 225 | 226 | @test "COMMENT_REGEX: should fail on invalid comment line" { 227 | # 228 | # Default delim 229 | # 230 | 231 | reset_delims 232 | reset_template_regexes 233 | 234 | [[ ! "" =~ $COMMENT_REGEX ]] 235 | [[ ! "comment" =~ $COMMENT_REGEX ]] 236 | [[ ! ".#comment" =~ $COMMENT_REGEX ]] 237 | 238 | # 239 | # Custom delim 240 | # 241 | 242 | parse_comment_delim '//' 243 | reset_template_regexes 244 | 245 | [[ ! "#comment" =~ $COMMENT_REGEX ]] 246 | } 247 | 248 | @test "COMMENT_REGEX: should match on valid comment line" { 249 | # 250 | # Default delim 251 | # 252 | 253 | reset_delims 254 | reset_template_regexes 255 | 256 | [[ "%# Comment" =~ $COMMENT_REGEX ]] 257 | [[ "${BASH_REMATCH[1]}" == '' ]] 258 | 259 | [[ " %# Comment" =~ $COMMENT_REGEX ]] 260 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 261 | 262 | [[ "%#Comment" =~ $COMMENT_REGEX ]] 263 | [[ "${BASH_REMATCH[1]}" == '' ]] 264 | 265 | [[ " %#Comment" =~ $COMMENT_REGEX ]] 266 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 267 | 268 | # 269 | # Custom delim 270 | # 271 | 272 | parse_comment_delim '//' 273 | reset_template_regexes 274 | 275 | [[ "// Comment" =~ $COMMENT_REGEX ]] 276 | [[ "${BASH_REMATCH[1]}" == '' ]] 277 | 278 | [[ " // Comment" =~ $COMMENT_REGEX ]] 279 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 280 | 281 | [[ "//Comment" =~ $COMMENT_REGEX ]] 282 | [[ "${BASH_REMATCH[1]}" == '' ]] 283 | 284 | [[ " //Comment" =~ $COMMENT_REGEX ]] 285 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 286 | } 287 | 288 | @test "STATEMENT_REGEX: should fail on invalid statement line" { 289 | # 290 | # Default delim 291 | # 292 | 293 | reset_delims 294 | reset_template_regexes 295 | 296 | [[ ! "" =~ $STATEMENT_REGEX ]] 297 | [[ ! "statement" =~ $STATEMENT_REGEX ]] 298 | [[ ! "%" =~ $STATEMENT_REGEX ]] 299 | [[ ! "%statement" =~ $STATEMENT_REGEX ]] 300 | 301 | parse_stmt_delim '$>' 302 | reset_template_regexes 303 | 304 | [[ ! "$" =~ $STATEMENT_REGEX ]] 305 | [[ ! "$>" =~ $STATEMENT_REGEX ]] 306 | [[ ! "$>statement" =~ $STATEMENT_REGEX ]] 307 | [[ ! "% statement" =~ $STATEMENT_REGEX ]] 308 | } 309 | 310 | @test "STATEMENT_REGEX: should match on valid statement line" { 311 | # 312 | # Default delim 313 | # 314 | 315 | reset_delims 316 | reset_template_regexes 317 | 318 | [[ "% statement" =~ $STATEMENT_REGEX ]] 319 | [[ "${BASH_REMATCH[1]}" == '' ]] 320 | [[ "${BASH_REMATCH[2]}" == 'statement' ]] 321 | 322 | [[ " % statement" =~ $STATEMENT_REGEX ]] 323 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 324 | [[ "${BASH_REMATCH[2]}" == 'statement' ]] 325 | 326 | [[ " % statement with args" =~ $STATEMENT_REGEX ]] 327 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 328 | [[ "${BASH_REMATCH[2]}" == 'statement with args' ]] 329 | 330 | # 331 | # Custom delim 332 | # 333 | 334 | parse_stmt_delim '$>' 335 | reset_template_regexes 336 | 337 | [[ "$> statement" =~ $STATEMENT_REGEX ]] 338 | [[ "${BASH_REMATCH[1]}" == '' ]] 339 | [[ "${BASH_REMATCH[2]}" == 'statement' ]] 340 | 341 | [[ " $> statement with args" =~ $STATEMENT_REGEX ]] 342 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 343 | [[ "${BASH_REMATCH[2]}" == 'statement with args' ]] 344 | } 345 | 346 | @test "STATEMENT_BLOCK_START_REGEX: should fail on invalid statement block start line" { 347 | # 348 | # Default delim 349 | # 350 | 351 | reset_delims 352 | reset_template_regexes 353 | 354 | [[ ! "" =~ $STATEMENT_BLOCK_START_REGEX ]] 355 | [[ ! "." =~ $STATEMENT_BLOCK_START_REGEX ]] 356 | [[ ! "%statement" =~ $STATEMENT_BLOCK_START_REGEX ]] 357 | 358 | # 359 | # Custom delim 360 | # 361 | 362 | parse_stmt_block_delims '<% %>' 363 | reset_template_regexes 364 | 365 | [[ ! "<" =~ $STATEMENT_BLOCK_START_REGEX ]] 366 | [[ ! "%" =~ $STATEMENT_BLOCK_START_REGEX ]] 367 | [[ ! "<%statement" =~ $STATEMENT_BLOCK_START_REGEX ]] 368 | 369 | } 370 | 371 | @test "STATEMENT_BLOCK_START_REGEX: should match on valid statement block start line" { 372 | # 373 | # Default delim 374 | # 375 | 376 | reset_delims 377 | reset_template_regexes 378 | 379 | [[ "%" =~ $STATEMENT_BLOCK_START_REGEX ]] 380 | [[ "${BASH_REMATCH[1]}" == '' ]] 381 | 382 | [[ "% " =~ $STATEMENT_BLOCK_START_REGEX ]] 383 | [[ "${BASH_REMATCH[1]}" == '' ]] 384 | 385 | [[ " %" =~ $STATEMENT_BLOCK_START_REGEX ]] 386 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 387 | 388 | [[ " % " =~ $STATEMENT_BLOCK_START_REGEX ]] 389 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 390 | 391 | # 392 | # Custom delim 393 | # 394 | 395 | parse_stmt_block_delims '<% %>' 396 | reset_template_regexes 397 | 398 | [[ "<%" =~ $STATEMENT_BLOCK_START_REGEX ]] 399 | [[ "${BASH_REMATCH[1]}" == '' ]] 400 | 401 | [[ "<% " =~ $STATEMENT_BLOCK_START_REGEX ]] 402 | [[ "${BASH_REMATCH[1]}" == '' ]] 403 | 404 | [[ " <%" =~ $STATEMENT_BLOCK_START_REGEX ]] 405 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 406 | 407 | [[ " <% " =~ $STATEMENT_BLOCK_START_REGEX ]] 408 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 409 | } 410 | 411 | @test "STATEMENT_BLOCK_STOP_REGEX: should fail on invalid statement block stop line" { 412 | # 413 | # Default delim 414 | # 415 | 416 | reset_delims 417 | reset_template_regexes 418 | 419 | [[ ! "" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 420 | [[ ! "." =~ $STATEMENT_BLOCK_STOP_REGEX ]] 421 | [[ ! "%statement" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 422 | 423 | # 424 | # Custom delim 425 | # 426 | 427 | parse_stmt_block_delims '<% %>' 428 | reset_template_regexes 429 | 430 | [[ ! ">" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 431 | [[ ! "%" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 432 | [[ ! "%>statement" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 433 | } 434 | 435 | @test "STATEMENT_BLOCK_STOP_REGEX: should match on valid statement block stop line" { 436 | # 437 | # Default delim 438 | # 439 | 440 | reset_delims 441 | reset_template_regexes 442 | 443 | [[ "%" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 444 | [[ "${BASH_REMATCH[1]}" == '' ]] 445 | 446 | [[ "% " =~ $STATEMENT_BLOCK_STOP_REGEX ]] 447 | [[ "${BASH_REMATCH[1]}" == '' ]] 448 | 449 | [[ " %" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 450 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 451 | 452 | [[ " % " =~ $STATEMENT_BLOCK_STOP_REGEX ]] 453 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 454 | 455 | # 456 | # Custom delim 457 | # 458 | 459 | parse_stmt_block_delims '<% %>' 460 | reset_template_regexes 461 | 462 | [[ "%>" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 463 | [[ "${BASH_REMATCH[1]}" == '' ]] 464 | 465 | [[ "%> " =~ $STATEMENT_BLOCK_STOP_REGEX ]] 466 | [[ "${BASH_REMATCH[1]}" == '' ]] 467 | 468 | [[ " %>" =~ $STATEMENT_BLOCK_STOP_REGEX ]] 469 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 470 | 471 | [[ " %> " =~ $STATEMENT_BLOCK_STOP_REGEX ]] 472 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 473 | 474 | } 475 | 476 | @test "STATEMENT_BLOCK_TEXT_REGEX: should fail on invalid text line" { 477 | # 478 | # Default delim 479 | # 480 | 481 | reset_delims 482 | reset_template_regexes 483 | 484 | [[ ! "" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 485 | [[ ! "text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 486 | [[ ! ".% text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 487 | 488 | # 489 | # Custom delim 490 | # 491 | 492 | parse_text_delim '>>' 493 | reset_template_regexes 494 | 495 | [[ ! "% text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 496 | } 497 | 498 | @test "STATEMENT_BLOCK_TEXT_REGEX: should match on valid text line" { 499 | # 500 | # Default delim 501 | # 502 | 503 | reset_delims 504 | reset_template_regexes 505 | 506 | [[ "% Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 507 | [[ "${BASH_REMATCH[1]}" == '' ]] 508 | 509 | [[ " % Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 510 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 511 | 512 | [[ "% Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 513 | [[ "${BASH_REMATCH[1]}" == '' ]] 514 | 515 | [[ " % Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 516 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 517 | 518 | # 519 | # Custom delim 520 | # 521 | 522 | parse_text_delim '>>' 523 | reset_template_regexes 524 | 525 | [[ ">> Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 526 | [[ "${BASH_REMATCH[1]}" == '' ]] 527 | 528 | [[ " >> Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 529 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 530 | 531 | [[ ">>Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 532 | [[ "${BASH_REMATCH[1]}" == '' ]] 533 | 534 | [[ " >>Text" =~ $STATEMENT_BLOCK_TEXT_REGEX ]] 535 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 536 | } 537 | 538 | @test "TEXT_REGEX: should match ALL input" { 539 | reset_delims 540 | reset_template_regexes 541 | 542 | [[ "" =~ $TEXT_REGEX ]] 543 | [[ "${BASH_REMATCH[1]}" == '' ]] 544 | [[ "${BASH_REMATCH[2]}" == '' ]] 545 | 546 | [[ " " =~ $TEXT_REGEX ]] 547 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 548 | [[ "${BASH_REMATCH[2]}" == '' ]] 549 | 550 | [[ " " =~ $TEXT_REGEX ]] 551 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 552 | [[ "${BASH_REMATCH[2]}" == '' ]] 553 | 554 | [[ " " =~ $TEXT_REGEX ]] 555 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 556 | [[ "${BASH_REMATCH[2]}" == '' ]] 557 | 558 | [[ "%" =~ $TEXT_REGEX ]] 559 | [[ "${BASH_REMATCH[1]}" == '' ]] 560 | [[ "${BASH_REMATCH[2]}" == '%' ]] 561 | 562 | [[ " %" =~ $TEXT_REGEX ]] 563 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 564 | [[ "${BASH_REMATCH[2]}" == '%' ]] 565 | 566 | [[ " % " =~ $TEXT_REGEX ]] 567 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 568 | [[ "${BASH_REMATCH[2]}" == '% ' ]] 569 | 570 | [[ "ab" =~ $TEXT_REGEX ]] 571 | [[ "${BASH_REMATCH[1]}" == '' ]] 572 | [[ "${BASH_REMATCH[2]}" == 'ab' ]] 573 | 574 | [[ " ab" =~ $TEXT_REGEX ]] 575 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 576 | [[ "${BASH_REMATCH[2]}" == 'ab' ]] 577 | 578 | [[ "ab " =~ $TEXT_REGEX ]] 579 | [[ "${BASH_REMATCH[1]}" == '' ]] 580 | [[ "${BASH_REMATCH[2]}" == 'ab ' ]] 581 | 582 | [[ " ab " =~ $TEXT_REGEX ]] 583 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 584 | [[ "${BASH_REMATCH[2]}" == 'ab ' ]] 585 | 586 | [[ "a b c" =~ $TEXT_REGEX ]] 587 | [[ "${BASH_REMATCH[1]}" == '' ]] 588 | [[ "${BASH_REMATCH[2]}" == 'a b c' ]] 589 | 590 | [[ " a b c" =~ $TEXT_REGEX ]] 591 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 592 | [[ "${BASH_REMATCH[2]}" == 'a b c' ]] 593 | 594 | [[ "a b c " =~ $TEXT_REGEX ]] 595 | [[ "${BASH_REMATCH[1]}" == '' ]] 596 | [[ "${BASH_REMATCH[2]}" == 'a b c ' ]] 597 | 598 | [[ " a b c " =~ $TEXT_REGEX ]] 599 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 600 | [[ "${BASH_REMATCH[2]}" == 'a b c ' ]] 601 | } 602 | 603 | 604 | @test "TAG_TEXT_REGEX: should fail on invalid text tag" { 605 | # 606 | # Default Delims 607 | # 608 | 609 | reset_delims 610 | reset_template_regexes 611 | 612 | [[ ! "" =~ $TAG_TEXT_REGEX ]] 613 | [[ ! "<<" =~ $TAG_TEXT_REGEX ]] 614 | [[ ! "<%" =~ $TAG_TEXT_REGEX ]] 615 | 616 | # 617 | # Custom Delims 618 | # 619 | 620 | parse_tag_delims "{{ }}" 621 | reset_template_regexes 622 | 623 | [[ ! "" =~ $TAG_TEXT_REGEX ]] 624 | [[ ! "{{" =~ $TAG_TEXT_REGEX ]] 625 | } 626 | 627 | @test "TAG_TEXT_REGEX: should match on valid text tag" { 628 | # 629 | # Default Delims 630 | # 631 | 632 | reset_delims 633 | reset_template_regexes 634 | 635 | [[ " " =~ $TAG_TEXT_REGEX ]] 636 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 637 | [[ "${BASH_REMATCH[2]}" == '' ]] 638 | 639 | [[ "<" =~ $TAG_TEXT_REGEX ]] 640 | [[ "${BASH_REMATCH[1]}" == '<' ]] 641 | [[ "${BASH_REMATCH[2]}" == '' ]] 642 | 643 | [[ "< " =~ $TAG_TEXT_REGEX ]] 644 | [[ "${BASH_REMATCH[1]}" == '< ' ]] 645 | [[ "${BASH_REMATCH[2]}" == '' ]] 646 | 647 | [[ " <" =~ $TAG_TEXT_REGEX ]] 648 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 649 | [[ "${BASH_REMATCH[2]}" == '<' ]] 650 | 651 | [[ " <<" =~ $TAG_TEXT_REGEX ]] 652 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 653 | [[ "${BASH_REMATCH[2]}" == '<<' ]] 654 | 655 | [[ " <%" =~ $TAG_TEXT_REGEX ]] 656 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 657 | [[ "${BASH_REMATCH[2]}" == '<%' ]] 658 | 659 | [[ "some text" =~ $TAG_TEXT_REGEX ]] 660 | [[ "${BASH_REMATCH[1]}" == 'some text' ]] 661 | [[ "${BASH_REMATCH[2]}" == '' ]] 662 | 663 | [[ "some text <" =~ $TAG_TEXT_REGEX ]] 664 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 665 | [[ "${BASH_REMATCH[2]}" == '<' ]] 666 | 667 | [[ "some text < " =~ $TAG_TEXT_REGEX ]] 668 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 669 | [[ "${BASH_REMATCH[2]}" == '< ' ]] 670 | 671 | [[ "some text <<" =~ $TAG_TEXT_REGEX ]] 672 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 673 | [[ "${BASH_REMATCH[2]}" == '<<' ]] 674 | 675 | [[ "some text <%" =~ $TAG_TEXT_REGEX ]] 676 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 677 | [[ "${BASH_REMATCH[2]}" == '<%' ]] 678 | 679 | [[ "some text <% " =~ $TAG_TEXT_REGEX ]] 680 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 681 | [[ "${BASH_REMATCH[2]}" == '<% ' ]] 682 | 683 | # 684 | # Custom Delims 685 | # 686 | 687 | parse_tag_delims "{{ }}" 688 | reset_template_regexes 689 | 690 | [[ "{" =~ $TAG_TEXT_REGEX ]] 691 | [[ "${BASH_REMATCH[1]}" == '{' ]] 692 | [[ "${BASH_REMATCH[2]}" == '' ]] 693 | 694 | [[ "{ " =~ $TAG_TEXT_REGEX ]] 695 | [[ "${BASH_REMATCH[1]}" == '{ ' ]] 696 | [[ "${BASH_REMATCH[2]}" == '' ]] 697 | 698 | [[ " {{" =~ $TAG_TEXT_REGEX ]] 699 | [[ "${BASH_REMATCH[1]}" == ' ' ]] 700 | [[ "${BASH_REMATCH[2]}" == '{{' ]] 701 | 702 | [[ "some text {" =~ $TAG_TEXT_REGEX ]] 703 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 704 | [[ "${BASH_REMATCH[2]}" == '{' ]] 705 | 706 | [[ "some text { " =~ $TAG_TEXT_REGEX ]] 707 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 708 | [[ "${BASH_REMATCH[2]}" == '{ ' ]] 709 | 710 | [[ "some text {{" =~ $TAG_TEXT_REGEX ]] 711 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 712 | [[ "${BASH_REMATCH[2]}" == '{{' ]] 713 | 714 | [[ "some text {{ " =~ $TAG_TEXT_REGEX ]] 715 | [[ "${BASH_REMATCH[1]}" == 'some text ' ]] 716 | [[ "${BASH_REMATCH[2]}" == '{{ ' ]] 717 | } 718 | 719 | @test "TAG_STD_REGEX: should fail on invalid std script tag" { 720 | # 721 | # Default Delims 722 | # 723 | 724 | reset_delims 725 | reset_template_regexes 726 | 727 | [[ ! "" =~ $TAG_STD_REGEX ]] 728 | [[ ! " " =~ $TAG_STD_REGEX ]] 729 | [[ ! "<" =~ $TAG_STD_REGEX ]] 730 | [[ ! "<%" =~ $TAG_STD_REGEX ]] 731 | [[ ! "<%>" =~ $TAG_STD_REGEX ]] 732 | [[ ! "<% >" =~ $TAG_STD_REGEX ]] 733 | [[ ! "<% tag >" =~ $TAG_STD_REGEX ]] 734 | [[ ! "<% % >" =~ $TAG_STD_REGEX ]] 735 | 736 | [[ ! "<%%%>" =~ $TAG_STD_REGEX ]] # Caveat to make the regex work 737 | [[ ! "<% %%>" =~ $TAG_STD_REGEX ]] # Caveat to make the regex work 738 | [[ "<%%%%>" =~ $TAG_STD_REGEX ]] # Caveat to make the regex work 739 | 740 | [[ ! "<%|" =~ $TAG_STD_REGEX ]] 741 | [[ ! "<%|>" =~ $TAG_STD_REGEX ]] 742 | [[ ! "<%| >" =~ $TAG_STD_REGEX ]] 743 | [[ ! "<%| tag >" =~ $TAG_STD_REGEX ]] 744 | [[ ! "<%| % >" =~ $TAG_STD_REGEX ]] 745 | 746 | [[ ! "<%|%%>" =~ $TAG_STD_REGEX ]] # Caveat to make the regex work 747 | [[ ! "<%| %%>" =~ $TAG_STD_REGEX ]] # Caveat to make the regex work 748 | [[ "<%|%%%>" =~ $TAG_STD_REGEX ]] # Caveat to make the regex work 749 | 750 | [[ "<% ||%>" =~ $TAG_STD_REGEX ]] 751 | 752 | # 753 | # Custom Delims 754 | # 755 | 756 | parse_tag_delims "{{ }}" 757 | parse_tag_fmt_delims "[ ]" 758 | reset_template_regexes 759 | 760 | [[ ! "{" =~ $TAG_STD_REGEX ]] 761 | [[ ! "{}" =~ $TAG_STD_REGEX ]] 762 | [[ ! "{{" =~ $TAG_STD_REGEX ]] 763 | [[ ! "{{}" =~ $TAG_STD_REGEX ]] 764 | [[ ! "{}}" =~ $TAG_STD_REGEX ]] 765 | [[ ! "{{ }" =~ $TAG_STD_REGEX ]] 766 | [[ ! "{ }}" =~ $TAG_STD_REGEX ]] 767 | [[ ! "{ }" =~ $TAG_STD_REGEX ]] 768 | [[ ! "{{ tag }" =~ $TAG_STD_REGEX ]] 769 | [[ ! "{{ } }" =~ $TAG_STD_REGEX ]] 770 | 771 | [[ ! "{[" =~ $TAG_STD_REGEX ]] 772 | [[ ! "{[}" =~ $TAG_STD_REGEX ]] 773 | [[ ! "{{[" =~ $TAG_STD_REGEX ]] 774 | [[ ! "{{[}" =~ $TAG_STD_REGEX ]] 775 | [[ ! "{[}}" =~ $TAG_STD_REGEX ]] 776 | [[ ! "{{[ }" =~ $TAG_STD_REGEX ]] 777 | [[ ! "{[ }}" =~ $TAG_STD_REGEX ]] 778 | [[ ! "{[ }" =~ $TAG_STD_REGEX ]] 779 | [[ ! "{{[ tag }" =~ $TAG_STD_REGEX ]] 780 | [[ ! "{{[ } }" =~ $TAG_STD_REGEX ]] 781 | 782 | [[ ! "{{ []}" =~ $TAG_STD_REGEX ]] 783 | } 784 | 785 | @test "TAG_STD_REGEX: should match on valid std script tag" { 786 | # 787 | # Default Delims 788 | # 789 | 790 | reset_delims 791 | reset_template_regexes 792 | 793 | [[ "<%%>" =~ $TAG_STD_REGEX ]] 794 | [[ "<% %>" =~ $TAG_STD_REGEX ]] 795 | [[ "<% %>" =~ $TAG_STD_REGEX ]] 796 | [[ "<%tag%>" =~ $TAG_STD_REGEX ]] 797 | [[ "<% tag%>" =~ $TAG_STD_REGEX ]] 798 | [[ "<%tag %>" =~ $TAG_STD_REGEX ]] 799 | [[ "<% tag %>" =~ $TAG_STD_REGEX ]] 800 | [[ "<%% %>" =~ $TAG_STD_REGEX ]] 801 | [[ "<% % %>" =~ $TAG_STD_REGEX ]] 802 | [[ '<% $HOME %>' =~ $TAG_STD_REGEX ]] 803 | 804 | [[ "<%%%%>" =~ $TAG_STD_REGEX ]] 805 | 806 | 807 | [[ "<%%>" =~ $TAG_STD_REGEX ]] 808 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 809 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 810 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 811 | 812 | [[ "<%text%>end" =~ $TAG_STD_REGEX ]] 813 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 814 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 815 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == 'end' ]] 816 | 817 | [[ "<%||%>" =~ $TAG_STD_REGEX ]] 818 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 819 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 820 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 821 | 822 | [[ "<%| |%>" =~ $TAG_STD_REGEX ]] 823 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == ' ' ]] 824 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 825 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 826 | 827 | [[ "<% | | %>" =~ $TAG_STD_REGEX ]] 828 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == ' ' ]] 829 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' ' ]] 830 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 831 | 832 | [[ "<%|%|%>" =~ $TAG_STD_REGEX ]] 833 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '%' ]] 834 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 835 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 836 | 837 | [[ "<%| % |%>" =~ $TAG_STD_REGEX ]] 838 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == ' % ' ]] 839 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 840 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 841 | 842 | [[ "<%|%format|%>" =~ $TAG_STD_REGEX ]] 843 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '%format' ]] 844 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 845 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 846 | 847 | [[ '<%|${format}|text%>end' =~ $TAG_STD_REGEX ]] 848 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '${format}' ]] 849 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 850 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == 'end' ]] 851 | 852 | # 853 | # Custom Delims 854 | # 855 | 856 | parse_tag_delims "{{ }}" 857 | parse_tag_fmt_delims "[ ]" 858 | reset_template_regexes 859 | 860 | [[ "{{}}" =~ $TAG_STD_REGEX ]] 861 | [[ "{{ }}" =~ $TAG_STD_REGEX ]] 862 | [[ "{{ }}" =~ $TAG_STD_REGEX ]] 863 | [[ "{{tag}}" =~ $TAG_STD_REGEX ]] 864 | [[ "{{ tag}}" =~ $TAG_STD_REGEX ]] 865 | [[ "{{tag }}" =~ $TAG_STD_REGEX ]] 866 | [[ "{{ tag }}>" =~ $TAG_STD_REGEX ]] 867 | 868 | [[ "{{}}}" =~ $TAG_STD_REGEX ]] 869 | [[ "{{} }}" =~ $TAG_STD_REGEX ]] 870 | [[ "{{ } }}" =~ $TAG_STD_REGEX ]] 871 | 872 | [[ "{{}}" =~ $TAG_STD_REGEX ]] 873 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 874 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 875 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 876 | 877 | [[ "{{text}}end" =~ $TAG_STD_REGEX ]] 878 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 879 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 880 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == 'end' ]] 881 | 882 | [[ "{{ }}}" =~ $TAG_STD_REGEX ]] 883 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 884 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 885 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}' ]] 886 | 887 | [[ "{{}}}}}" =~ $TAG_STD_REGEX ]] 888 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 889 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 890 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}}}' ]] 891 | 892 | [[ "{{[]}}" =~ $TAG_STD_REGEX ]] 893 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 894 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 895 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 896 | 897 | [[ "{{ [] }}" =~ $TAG_STD_REGEX ]] 898 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 899 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' ' ]] 900 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 901 | 902 | [[ "{{[%]}}" =~ $TAG_STD_REGEX ]] 903 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '%' ]] 904 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 905 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 906 | 907 | [[ "{{[%format]text}}end" =~ $TAG_STD_REGEX ]] 908 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '%format' ]] 909 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 910 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == 'end' ]] 911 | 912 | [[ '{{[${format}]}}' =~ $TAG_STD_REGEX ]] 913 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '${format}' ]] 914 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 915 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '' ]] 916 | 917 | [[ "{{[] }}}" =~ $TAG_STD_REGEX ]] 918 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 919 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' ' ]] 920 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}' ]] 921 | 922 | [[ "{{[]}}}}}" =~ $TAG_STD_REGEX ]] 923 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 924 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '' ]] 925 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}}}' ]] 926 | } 927 | 928 | @test "TAG_STD_REGEX: should only match 1st tag if multiple tags present" { 929 | # 930 | # Default Delims 931 | # 932 | 933 | reset_delims 934 | reset_template_regexes 935 | 936 | [[ "<% . %>." =~ $TAG_STD_REGEX ]] 937 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 938 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 939 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.' ]] 940 | 941 | [[ "<% . %><" =~ $TAG_STD_REGEX ]] 942 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 943 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 944 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '<' ]] 945 | 946 | [[ "<% . %>%" =~ $TAG_STD_REGEX ]] 947 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 948 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 949 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '%' ]] 950 | 951 | [[ "<% . %><%" =~ $TAG_STD_REGEX ]] 952 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 953 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 954 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '<%' ]] 955 | 956 | [[ "<% . %>>" =~ $TAG_STD_REGEX ]] 957 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 958 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 959 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '>' ]] 960 | 961 | [[ "<% . %>%>" =~ $TAG_STD_REGEX ]] 962 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 963 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 964 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '%>' ]] 965 | 966 | [[ "<% . %><% . %>" =~ $TAG_STD_REGEX ]] 967 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 968 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 969 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '<% . %>' ]] 970 | 971 | [[ "<% . %>.<% . %>" =~ $TAG_STD_REGEX ]] 972 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 973 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 974 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.<% . %>' ]] 975 | 976 | [[ "<%|| . %>." =~ $TAG_STD_REGEX ]] 977 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 978 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 979 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.' ]] 980 | 981 | [[ "<%|| . %><" =~ $TAG_STD_REGEX ]] 982 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 983 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 984 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '<' ]] 985 | 986 | [[ "<%|| . %>%" =~ $TAG_STD_REGEX ]] 987 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 988 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 989 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '%' ]] 990 | 991 | [[ "<%|| . %><%" =~ $TAG_STD_REGEX ]] 992 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 993 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 994 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '<%' ]] 995 | 996 | [[ "<%|| . %>>" =~ $TAG_STD_REGEX ]] 997 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 998 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 999 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '>' ]] 1000 | 1001 | [[ "<%|| . %>%>" =~ $TAG_STD_REGEX ]] 1002 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1003 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1004 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '%>' ]] 1005 | 1006 | [[ "<%|| . %><% . %>" =~ $TAG_STD_REGEX ]] 1007 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1008 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1009 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '<% . %>' ]] 1010 | 1011 | [[ "<%|| . %>.<% . %>" =~ $TAG_STD_REGEX ]] 1012 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1013 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1014 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.<% . %>' ]] 1015 | 1016 | [[ "<%|%format|text%>.<% . %>" =~ $TAG_STD_REGEX ]] 1017 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '%format' ]] 1018 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 1019 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.<% . %>' ]] 1020 | 1021 | [[ '<%|${format}|text%>.<% . %>' =~ $TAG_STD_REGEX ]] 1022 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '${format}' ]] 1023 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 1024 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.<% . %>' ]] 1025 | 1026 | # 1027 | # Custom Delims 1028 | # 1029 | 1030 | parse_tag_delims "{{ }}" 1031 | parse_tag_fmt_delims "[ ]" 1032 | reset_template_regexes 1033 | 1034 | [[ "{{ . }}." =~ $TAG_STD_REGEX ]] 1035 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1036 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 1037 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.' ]] 1038 | 1039 | [[ "{{ . }}{" =~ $TAG_STD_REGEX ]] 1040 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1041 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 1042 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '{' ]] 1043 | 1044 | [[ "{{ . }}{{" =~ $TAG_STD_REGEX ]] 1045 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1046 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 1047 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '{{' ]] 1048 | 1049 | [[ "{{ . }}}" =~ $TAG_STD_REGEX ]] 1050 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1051 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 1052 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}' ]] 1053 | 1054 | [[ "{{ . }}}}" =~ $TAG_STD_REGEX ]] 1055 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1056 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 1057 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}}' ]] 1058 | 1059 | [[ "{{ . }}{{ . }}" =~ $TAG_STD_REGEX ]] 1060 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1061 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 1062 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '{{ . }}' ]] 1063 | 1064 | [[ "{{ . }}.{{ . }}" =~ $TAG_STD_REGEX ]] 1065 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1066 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == '. ' ]] 1067 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.{{ . }}' ]] 1068 | 1069 | [[ "{{[] . }}." =~ $TAG_STD_REGEX ]] 1070 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1071 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1072 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.' ]] 1073 | 1074 | [[ "{{[] . }}{" =~ $TAG_STD_REGEX ]] 1075 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1076 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1077 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '{' ]] 1078 | 1079 | [[ "{{[] . }}{{" =~ $TAG_STD_REGEX ]] 1080 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1081 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1082 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '{{' ]] 1083 | 1084 | [[ "{{[] . }}}" =~ $TAG_STD_REGEX ]] 1085 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1086 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1087 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}' ]] 1088 | 1089 | [[ "{{[] . }}}}" =~ $TAG_STD_REGEX ]] 1090 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1091 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1092 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '}}' ]] 1093 | 1094 | [[ "{{[] . }}{{ . }}" =~ $TAG_STD_REGEX ]] 1095 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1096 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1097 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '{{ . }}' ]] 1098 | 1099 | [[ "{{[] . }}.{{ . }}" =~ $TAG_STD_REGEX ]] 1100 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '' ]] 1101 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == ' . ' ]] 1102 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.{{ . }}' ]] 1103 | 1104 | [[ "{{[%format]text}}.{{ . }}" =~ $TAG_STD_REGEX ]] 1105 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '%format' ]] 1106 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 1107 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.{{ . }}' ]] 1108 | 1109 | [[ '{{[${format}]text}}.{{ . }}' =~ $TAG_STD_REGEX ]] 1110 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_FMT}]}" == '${format}' ]] 1111 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_TXT}]}" == 'text' ]] 1112 | [[ "${BASH_REMATCH[${TAG_STD_MATCH_IDX_END}]}" == '.{{ . }}' ]] 1113 | } 1114 | 1115 | @test "TAG_QUOTE_REGEX: should fail on invalid quote script tag" { 1116 | # 1117 | # Default Delims 1118 | # 1119 | 1120 | reset_delims 1121 | reset_template_regexes 1122 | 1123 | [[ ! "" =~ $TAG_QUOTE_REGEX ]] 1124 | [[ ! " " =~ $TAG_QUOTE_REGEX ]] 1125 | [[ ! "<" =~ $TAG_QUOTE_REGEX ]] 1126 | [[ ! "<>" =~ $TAG_QUOTE_REGEX ]] 1127 | [[ ! "<%" =~ $TAG_QUOTE_REGEX ]] 1128 | [[ ! "<%>" =~ $TAG_QUOTE_REGEX ]] 1129 | [[ ! "<% %>" =~ $TAG_QUOTE_REGEX ]] 1130 | [[ ! "<% tag %>" =~ $TAG_QUOTE_REGEX ]] 1131 | [[ ! '<%"%>' =~ $TAG_QUOTE_REGEX ]] 1132 | [[ '<%" " %>' =~ $TAG_QUOTE_REGEX ]] 1133 | [[ '<% " " %>' =~ $TAG_QUOTE_REGEX ]] 1134 | [[ ! '<%"""%>' =~ $TAG_QUOTE_REGEX ]] # Caveat to make the regex work 1135 | [[ ! '<%" ""%>' =~ $TAG_QUOTE_REGEX ]] # Caveat to make the regex work 1136 | [[ ! '<%"""""%>' =~ $TAG_QUOTE_REGEX ]] # Caveat to make the regex work 1137 | 1138 | # 1139 | # Custom Delims 1140 | # 1141 | 1142 | parse_tag_delims "{{ }}" 1143 | reset_template_regexes 1144 | 1145 | [[ ! "{" =~ $TAG_QUOTE_REGEX ]] 1146 | [[ ! "{}" =~ $TAG_QUOTE_REGEX ]] 1147 | [[ ! "{{" =~ $TAG_QUOTE_REGEX ]] 1148 | [[ ! "{{}" =~ $TAG_QUOTE_REGEX ]] 1149 | [[ ! "{}}" =~ $TAG_QUOTE_REGEX ]] 1150 | [[ ! "{{ }}" =~ $TAG_QUOTE_REGEX ]] 1151 | [[ ! "{{ tag }}" =~ $TAG_QUOTE_REGEX ]] 1152 | [[ ! '{{"}}' =~ $TAG_QUOTE_REGEX ]] 1153 | [[ '{{" " }}' =~ $TAG_QUOTE_REGEX ]] 1154 | [[ '{{ " "}}' =~ $TAG_QUOTE_REGEX ]] 1155 | [[ '{{ " " }}' =~ $TAG_QUOTE_REGEX ]] 1156 | } 1157 | 1158 | @test "TAG_QUOTE_REGEX: should match on valid quote script tag" { 1159 | # 1160 | # Default Delims 1161 | # 1162 | 1163 | reset_delims 1164 | reset_template_regexes 1165 | 1166 | [[ '<%""%>' =~ $TAG_QUOTE_REGEX ]] 1167 | 1168 | [[ '<%""%>' =~ $TAG_QUOTE_REGEX ]] 1169 | [[ '<% "" %>' =~ $TAG_QUOTE_REGEX ]] 1170 | [[ '<%" "%>' =~ $TAG_QUOTE_REGEX ]] 1171 | [[ '<% " " %>' =~ $TAG_QUOTE_REGEX ]] 1172 | [[ '<%"tag"%>' =~ $TAG_QUOTE_REGEX ]] 1173 | [[ '<% "tag" %>' =~ $TAG_QUOTE_REGEX ]] 1174 | [[ '<%" tag"%>' =~ $TAG_QUOTE_REGEX ]] 1175 | [[ '<%"tag "%>' =~ $TAG_QUOTE_REGEX ]] 1176 | [[ '<%" tag "%>' =~ $TAG_QUOTE_REGEX ]] 1177 | [[ '<%"" "%>' =~ $TAG_QUOTE_REGEX ]] 1178 | [[ '<%" " "%>' =~ $TAG_QUOTE_REGEX ]] 1179 | [[ '<%""""%>' =~ $TAG_QUOTE_REGEX ]] 1180 | 1181 | [[ '<%||""%>' =~ $TAG_QUOTE_REGEX ]] 1182 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1183 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1184 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1185 | 1186 | [[ '<% || "" %>' =~ $TAG_QUOTE_REGEX ]] 1187 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1188 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1189 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1190 | 1191 | [[ '<%|%|""%>' =~ $TAG_QUOTE_REGEX ]] 1192 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '%' ]] 1193 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1194 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1195 | 1196 | [[ '<%|%s|""%>' =~ $TAG_QUOTE_REGEX ]] 1197 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '%s' ]] 1198 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1199 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1200 | 1201 | [[ '<%|%format|"text"%>' =~ $TAG_QUOTE_REGEX ]] 1202 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '%format' ]] 1203 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == 'text' ]] 1204 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1205 | 1206 | [[ '<%|${format}|"text"%>' =~ $TAG_QUOTE_REGEX ]] 1207 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '${format}' ]] 1208 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == 'text' ]] 1209 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1210 | 1211 | [[ '<% |${format}| "text" %>' =~ $TAG_QUOTE_REGEX ]] 1212 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '${format}' ]] 1213 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == 'text' ]] 1214 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1215 | 1216 | # 1217 | # Custom Delims 1218 | # 1219 | 1220 | parse_tag_delims "{{ }}" 1221 | parse_tag_fmt_delims "[ ]" 1222 | reset_template_regexes 1223 | 1224 | [[ '{{""}}' =~ $TAG_QUOTE_REGEX ]] 1225 | [[ '{{ "" }}' =~ $TAG_QUOTE_REGEX ]] 1226 | [[ '{{" "}}' =~ $TAG_QUOTE_REGEX ]] 1227 | [[ '{{ " " }}' =~ $TAG_QUOTE_REGEX ]] 1228 | [[ '{{" "}}' =~ $TAG_QUOTE_REGEX ]] 1229 | [[ '{{"tag"}}' =~ $TAG_QUOTE_REGEX ]] 1230 | [[ '{{ "tag" }}' =~ $TAG_QUOTE_REGEX ]] 1231 | [[ '{{" tag"}}' =~ $TAG_QUOTE_REGEX ]] 1232 | [[ '{{"tag "}}' =~ $TAG_QUOTE_REGEX ]] 1233 | [[ '{{" tag "}}>' =~ $TAG_QUOTE_REGEX ]] 1234 | [[ '{{"" "}}' =~ $TAG_QUOTE_REGEX ]] 1235 | [[ '{{" " "}}' =~ $TAG_QUOTE_REGEX ]] 1236 | [[ '{{""""}}' =~ $TAG_QUOTE_REGEX ]] 1237 | 1238 | [[ '{{[]""}}' =~ $TAG_QUOTE_REGEX ]] 1239 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1240 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1241 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1242 | 1243 | [[ '{{ [] "" }}' =~ $TAG_QUOTE_REGEX ]] 1244 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1245 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1246 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1247 | 1248 | [[ '{{[%]""}}' =~ $TAG_QUOTE_REGEX ]] 1249 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '%' ]] 1250 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1251 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1252 | 1253 | [[ '{{[%s]""}}' =~ $TAG_QUOTE_REGEX ]] 1254 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '%s' ]] 1255 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '' ]] 1256 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1257 | 1258 | [[ '{{[%format]"text"}}' =~ $TAG_QUOTE_REGEX ]] 1259 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '%format' ]] 1260 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == 'text' ]] 1261 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1262 | 1263 | [[ '{{[${format}]"text"}}' =~ $TAG_QUOTE_REGEX ]] 1264 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '${format}' ]] 1265 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == 'text' ]] 1266 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1267 | 1268 | [[ '{{ [${format}] "text" }}' =~ $TAG_QUOTE_REGEX ]] 1269 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '${format}' ]] 1270 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == 'text' ]] 1271 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '' ]] 1272 | } 1273 | 1274 | @test "TAG_QUOTE_REGEX: should only match 1st tag if multiple tags present" { 1275 | # 1276 | # Default Delims 1277 | # 1278 | 1279 | reset_delims 1280 | reset_template_regexes 1281 | 1282 | [[ '<%"."%>.' =~ $TAG_QUOTE_REGEX ]] 1283 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1284 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1285 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '.' ]] 1286 | 1287 | [[ '<%"."%><' =~ $TAG_QUOTE_REGEX ]] 1288 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1289 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1290 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '<' ]] 1291 | 1292 | [[ '<%"."%><%' =~ $TAG_QUOTE_REGEX ]] 1293 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1294 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1295 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '<%' ]] 1296 | 1297 | [[ '<%"."%><%"' =~ $TAG_QUOTE_REGEX ]] 1298 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1299 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1300 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '<%"' ]] 1301 | 1302 | [[ '<%"."%>>' =~ $TAG_QUOTE_REGEX ]] 1303 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1304 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1305 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '>' ]] 1306 | 1307 | [[ '<%"."%>%>' =~ $TAG_QUOTE_REGEX ]] 1308 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1309 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1310 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '%>' ]] 1311 | 1312 | [[ '<%"."%>"' =~ $TAG_QUOTE_REGEX ]] 1313 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1314 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1315 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '"' ]] 1316 | 1317 | [[ '<%"."%>"%' =~ $TAG_QUOTE_REGEX ]] 1318 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1319 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1320 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '"%' ]] 1321 | 1322 | [[ '<%"."%>"%>' =~ $TAG_QUOTE_REGEX ]] 1323 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1324 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1325 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '"%>' ]] 1326 | 1327 | [[ '<%"."%><%"."%>' =~ $TAG_QUOTE_REGEX ]] 1328 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1329 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1330 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '<%"."%>' ]] 1331 | 1332 | [[ '<%"."%>.<%"."%>' =~ $TAG_QUOTE_REGEX ]] 1333 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1334 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1335 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '.<%"."%>' ]] 1336 | 1337 | # 1338 | # Custom Delims 1339 | # 1340 | 1341 | parse_tag_delims "{{ }}" 1342 | reset_template_regexes 1343 | 1344 | [[ '{{"."}}.' =~ $TAG_QUOTE_REGEX ]] 1345 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1346 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1347 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '.' ]] 1348 | 1349 | [[ '{{"."}}{' =~ $TAG_QUOTE_REGEX ]] 1350 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1351 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1352 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '{' ]] 1353 | 1354 | [[ '{{"."}}{{' =~ $TAG_QUOTE_REGEX ]] 1355 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1356 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1357 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '{{' ]] 1358 | 1359 | [[ '{{"."}}{{"' =~ $TAG_QUOTE_REGEX ]] 1360 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1361 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1362 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '{{"' ]] 1363 | 1364 | [[ '{{"."}}}' =~ $TAG_QUOTE_REGEX ]] 1365 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1366 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1367 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '}' ]] 1368 | 1369 | [[ '{{"."}}}}' =~ $TAG_QUOTE_REGEX ]] 1370 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1371 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1372 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '}}' ]] 1373 | 1374 | [[ '{{"."}}"' =~ $TAG_QUOTE_REGEX ]] 1375 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1376 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1377 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '"' ]] 1378 | 1379 | [[ '{{"."}}"}' =~ $TAG_QUOTE_REGEX ]] 1380 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1381 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1382 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '"}' ]] 1383 | 1384 | [[ '{{"."}}"}}' =~ $TAG_QUOTE_REGEX ]] 1385 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1386 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1387 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '"}}' ]] 1388 | 1389 | [[ '{{"."}}{{"."}}' =~ $TAG_QUOTE_REGEX ]] 1390 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1391 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1392 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '{{"."}}' ]] 1393 | 1394 | [[ '{{"."}}.{{"."}}' =~ $TAG_QUOTE_REGEX ]] 1395 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_FMT}]}" == '' ]] 1396 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_TXT}]}" == '.' ]] 1397 | [[ "${BASH_REMATCH[${TAG_QUOTE_MATCH_IDX_END}]}" == '.{{"."}}' ]] 1398 | } 1399 | 1400 | @test "TAG_STATEMENT_REGEX: should fail on invalid statement script tag" { 1401 | # 1402 | # Default Delims 1403 | # 1404 | 1405 | reset_delims 1406 | reset_template_regexes 1407 | 1408 | [[ ! "" =~ $TAG_STATEMENT_REGEX ]] 1409 | [[ ! " " =~ $TAG_STATEMENT_REGEX ]] 1410 | [[ ! "<" =~ $TAG_STATEMENT_REGEX ]] 1411 | [[ ! "<%" =~ $TAG_STATEMENT_REGEX ]] 1412 | [[ ! "<%>" =~ $TAG_STATEMENT_REGEX ]] 1413 | [[ ! "<% %>" =~ $TAG_STATEMENT_REGEX ]] 1414 | [[ ! "<% tag %>" =~ $TAG_STATEMENT_REGEX ]] 1415 | [[ "<% % %>" =~ $TAG_STATEMENT_REGEX ]] 1416 | [[ ! "<%% %%>" =~ $TAG_STATEMENT_REGEX ]] # TODO 1417 | 1418 | # 1419 | # Custom Delims 1420 | # 1421 | 1422 | parse_tag_stmt_delim "$" 1423 | reset_template_regexes 1424 | 1425 | [[ ! "<%% %>" =~ $TAG_STATEMENT_REGEX ]] 1426 | [[ "<% $ %>" =~ $TAG_STATEMENT_REGEX ]] 1427 | } 1428 | 1429 | @test "TAG_STATEMENT_REGEX: should match on valid statement script tag" { 1430 | # 1431 | # Default Delims 1432 | # 1433 | 1434 | reset_delims 1435 | reset_template_regexes 1436 | 1437 | [[ "<%%%>" =~ $TAG_STATEMENT_REGEX ]] 1438 | [[ "<%% %>" =~ $TAG_STATEMENT_REGEX ]] 1439 | [[ "<%% %>" =~ $TAG_STATEMENT_REGEX ]] 1440 | [[ "<%%tag%>" =~ $TAG_STATEMENT_REGEX ]] 1441 | [[ "<%% tag%>" =~ $TAG_STATEMENT_REGEX ]] 1442 | [[ "<%%tag %>" =~ $TAG_STATEMENT_REGEX ]] 1443 | [[ "<%% tag %>" =~ $TAG_STATEMENT_REGEX ]] 1444 | [[ "<%% %>" =~ $TAG_STATEMENT_REGEX ]] 1445 | [[ "<%% % %>" =~ $TAG_STATEMENT_REGEX ]] 1446 | 1447 | # 1448 | # Custom Delims 1449 | # 1450 | 1451 | parse_tag_stmt_delim "$" 1452 | reset_template_regexes 1453 | 1454 | [[ '<%$%>' =~ $TAG_STATEMENT_REGEX ]] 1455 | [[ '<%$ %>' =~ $TAG_STATEMENT_REGEX ]] 1456 | [[ '<%$ %>' =~ $TAG_STATEMENT_REGEX ]] 1457 | [[ '<%$tag%>' =~ $TAG_STATEMENT_REGEX ]] 1458 | [[ '<%$ tag%>' =~ $TAG_STATEMENT_REGEX ]] 1459 | [[ '<%$tag %>' =~ $TAG_STATEMENT_REGEX ]] 1460 | [[ '<%$ $tag %>' =~ $TAG_STATEMENT_REGEX ]] 1461 | [[ '<%$$ $%>' =~ $TAG_STATEMENT_REGEX ]] 1462 | [[ '<%$$ $ %>' =~ $TAG_STATEMENT_REGEX ]] 1463 | [[ '<%$$$%>' =~ $TAG_STATEMENT_REGEX ]] 1464 | } 1465 | 1466 | @test "TAG_STATEMENT_REGEX: should only match 1st tag if multiple tags present" { 1467 | # 1468 | # Default Delims 1469 | # 1470 | 1471 | reset_delims 1472 | reset_template_regexes 1473 | 1474 | [[ '<%%.%>.' =~ $TAG_STATEMENT_REGEX ]] 1475 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1476 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1477 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '.' ]] 1478 | 1479 | [[ '<%%.%><' =~ $TAG_STATEMENT_REGEX ]] 1480 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1481 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1482 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '<' ]] 1483 | 1484 | [[ '<%%.%><%' =~ $TAG_STATEMENT_REGEX ]] 1485 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1486 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1487 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '<%' ]] 1488 | 1489 | [[ '<%%.%><%%' =~ $TAG_STATEMENT_REGEX ]] 1490 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1491 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1492 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '<%%' ]] 1493 | 1494 | [[ '<%%.%>>' =~ $TAG_STATEMENT_REGEX ]] 1495 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1496 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1497 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '>' ]] 1498 | 1499 | [[ '<%%.%>%>' =~ $TAG_STATEMENT_REGEX ]] 1500 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1501 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1502 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '%>' ]] 1503 | 1504 | [[ '<%%.%>"%' =~ $TAG_STATEMENT_REGEX ]] 1505 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1506 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1507 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '"%' ]] 1508 | 1509 | [[ '<%%.%><%%.%>' =~ $TAG_STATEMENT_REGEX ]] 1510 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1511 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1512 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '<%%.%>' ]] 1513 | 1514 | [[ '<%%.%>.<%%.%>' =~ $TAG_STATEMENT_REGEX ]] 1515 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1516 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1517 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '.<%%.%>' ]] 1518 | 1519 | # 1520 | # Custom Delims 1521 | # 1522 | 1523 | parse_tag_delims "{{ }}" 1524 | reset_template_regexes 1525 | 1526 | [[ '{{%.}}.' =~ $TAG_STATEMENT_REGEX ]] 1527 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1528 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1529 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '.' ]] 1530 | 1531 | [[ '{{%.}}{' =~ $TAG_STATEMENT_REGEX ]] 1532 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1533 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1534 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '{' ]] 1535 | 1536 | [[ '{{%.}}{{' =~ $TAG_STATEMENT_REGEX ]] 1537 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1538 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1539 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '{{' ]] 1540 | 1541 | [[ '{{%.}}{{%' =~ $TAG_STATEMENT_REGEX ]] 1542 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1543 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1544 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '{{%' ]] 1545 | 1546 | [[ '{{%.}}}' =~ $TAG_STATEMENT_REGEX ]] 1547 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1548 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1549 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '}' ]] 1550 | 1551 | [[ '{{%.}}}}' =~ $TAG_STATEMENT_REGEX ]] 1552 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1553 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1554 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '}}' ]] 1555 | 1556 | [[ '{{%.}}{{%.}}' =~ $TAG_STATEMENT_REGEX ]] 1557 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1558 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1559 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '{{%.}}' ]] 1560 | 1561 | [[ '{{%.}}.{{%.}}' =~ $TAG_STATEMENT_REGEX ]] 1562 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_FMT}]}" == '' ]] 1563 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_TXT}]}" == '.' ]] 1564 | [[ "${BASH_REMATCH[${TAG_STATEMENT_MATCH_IDX_END}]}" == '.{{%.}}' ]] 1565 | } 1566 | -------------------------------------------------------------------------------- /test/text_indents.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | # shellcheck source=../bash-tpl 5 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 6 | } 7 | 8 | @test "TEXT_INDENT: Should exist and be set to '' on init" { 9 | [[ "${TEXT_INDENT-.}" == "" ]] 10 | } 11 | 12 | @test "TEXT_INDENTS: Should exist and be empty on init" { 13 | [[ ${#TEXT_INDENTS[@]} -eq 0 ]] 14 | } 15 | 16 | @test "push_text_indent: Should add current TEXT_INDENT to tail of TEXT_INDENTS array, set TEXT_INDENT to new value" { 17 | push_text_indent "ONE" 18 | [[ ${TEXT_INDENT} == "ONE" ]] 19 | [[ ${#TEXT_INDENTS[@]} -eq 1 ]] 20 | [[ "${TEXT_INDENTS[0]}" == "" ]] 21 | 22 | push_text_indent "TWO" 23 | [[ ${TEXT_INDENT} == "TWO" ]] 24 | [[ ${#TEXT_INDENTS[@]} -eq 2 ]] 25 | [[ "${TEXT_INDENTS[0]}" == "" ]] 26 | [[ "${TEXT_INDENTS[1]}" == "ONE" ]] 27 | } 28 | 29 | @test "pop_text_indent: Should remove tail of TEXT_INDENTS array, setting TEXT_INDENT to removed value" { 30 | push_text_indent "ONE" 31 | push_text_indent "TWO" 32 | [[ ${TEXT_INDENT} == "TWO" ]] 33 | [[ ${#TEXT_INDENTS[@]} -eq 2 ]] 34 | [[ "${TEXT_INDENTS[0]}" == "" ]] 35 | [[ "${TEXT_INDENTS[1]}" == "ONE" ]] 36 | 37 | pop_text_indent 38 | [[ ${TEXT_INDENT} == "ONE" ]] 39 | [[ ${#TEXT_INDENTS[@]} -eq 1 ]] 40 | [[ "${TEXT_INDENTS[0]}" == "" ]] 41 | 42 | pop_text_indent 43 | [[ ${TEXT_INDENT} == "" ]] 44 | [[ ${#TEXT_INDENTS[@]} -eq 0 ]] 45 | } 46 | 47 | @test "pop_text_indent: Should set TEXT_INDENT to '', should not generate error when TEXT_INDENTS array is empty" { 48 | [[ ${TEXT_INDENT} == "" ]] 49 | [[ ${#TEXT_INDENTS[@]} -eq 0 ]] 50 | 51 | TEXT_INDENT="." 52 | pop_text_indent 53 | [[ ${TEXT_INDENT} == "" ]] 54 | [[ ${#TEXT_INDENTS[@]} -eq 0 ]] 55 | 56 | TEXT_INDENT="." 57 | pop_text_indent 58 | [[ ${TEXT_INDENT} == "" ]] 59 | [[ ${#TEXT_INDENTS[@]} -eq 0 ]] 60 | } 61 | -------------------------------------------------------------------------------- /test/tpl.bats.bats: -------------------------------------------------------------------------------- 1 | 2 | setup() { 3 | bats_require_minimum_version 1.7.0 4 | load lib/diff 5 | # shellcheck source=../bash-tpl 6 | source "${BATS_TEST_DIRNAME}/../bash-tpl" 7 | } 8 | 9 | # NOTE: We do not auto re-gen tpl.bats.sh because a failure 10 | # here could suggest a breaking change in bash-tpl 11 | # 12 | @test "tpl.bats.sh: Check if tpl.bats.sh is outdated" { 13 | pushd "${BATS_TEST_DIRNAME}" > /dev/null 14 | run main "${BATS_TEST_DIRNAME}/tpl.bats.tpl" 15 | diff_output_file "${BATS_TEST_DIRNAME}/tpl.bats.sh" 16 | popd > /dev/null 17 | } 18 | 19 | @test "tpl.bats: Should generate new copy of test/tpl.bats" { 20 | # Remove existing copy, if present 21 | # 22 | rm -f "${BATS_TEST_DIRNAME}/tpl/tpl.bats" 23 | [[ ! -f "${BATS_TEST_DIRNAME}/tpl/tpl.bats" ]] 24 | 25 | # Create new test suite against current tpl files 26 | # 27 | "${BATS_TEST_DIRNAME}/tpl.bats.sh" > "${BATS_TEST_DIRNAME}/tpl/tpl.bats" 28 | [[ -f "${BATS_TEST_DIRNAME}/tpl/tpl.bats" ]] 29 | } 30 | -------------------------------------------------------------------------------- /test/tpl.bats.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | pushd test/tpl >> /dev/null 3 | exec > tpl.bats 4 | printf "%b\n" '# NOTE: BATS_TEST_DIRNAME => BASH_TPL_ROOT/test/tpl' 5 | printf "%b\n" '#' 6 | printf "\n" 7 | printf "%b\n" 'setup() {' 8 | printf "%b\n" '\tbats_require_minimum_version 1.7.0' 9 | printf "%b\n" '\tload ../lib/diff' 10 | printf "%b\n" '\t# shellcheck source=../../bash-tpl' 11 | printf "%b\n" '\tsource "${BATS_TEST_DIRNAME}/../../bash-tpl"' 12 | printf "%b\n" '}' 13 | printf "\n" 14 | printf "%b\n" '##' 15 | printf "%b\n" '# test_template' 16 | printf "%b\n" '# $1 = template basename (no path)' 17 | printf "%b\n" '# Assumed to be relative to test/tpl' 18 | printf "%b\n" '#' 19 | printf "%b\n" 'test_template() {' 20 | printf "%b\n" '\tpushd "${BATS_TEST_DIRNAME}" >> /dev/null' 21 | printf "%b\n" '\tlocal separate_stderr=' 22 | printf "%b\n" '\t# Does test include check for stderr?' 23 | printf "%b\n" '\tif [ -f "${BATS_TEST_DIRNAME}/${1%.tpl}.stderr" ]; then' 24 | printf "%b\n" '\t\tseparate_stderr=\0047--separate-stderr\0047' 25 | printf "%b\n" '\tfi' 26 | printf "%b\n" '\trun ${separate_stderr} -- main "${BATS_TEST_DIRNAME}/${1}"' 27 | printf "%b\n" '\t[[ $status = 0 ]]' 28 | printf "%b\n" '\tdiff_output_file "${BATS_TEST_DIRNAME}/${1%.tpl}.sh"' 29 | printf "%b\n" '\tif [ "${output_type}" = "separate" ]; then' 30 | printf "%b\n" '\t\tdiff_stderr_file "${BATS_TEST_DIRNAME}/${1%.tpl}.stderr"' 31 | printf "%b\n" '\tfi' 32 | printf "%b\n" '\trun bash "${BATS_TEST_DIRNAME}/${1%.tpl}.sh"' 33 | printf "%b\n" '\tdiff_output_file "${BATS_TEST_DIRNAME}/${1%.tpl}.txt"' 34 | printf "%b\n" '\tpopd >> /dev/null' 35 | printf "%b\n" '}' 36 | _fix_nullglob=$(shopt -p nullglob || true) 37 | shopt -s nullglob 38 | for tpl in *.tpl; do 39 | printf "\n" 40 | printf "%b%s%b%s%b\n" '@test "tpl: Should render test/tpl/' "$tpl" ' to match test/tpl/' "${tpl%.tpl}.sh" ' {' 41 | printf "%b%s%b\n" '\ttest_template "' "$tpl" '"' 42 | printf "%b\n" '}' 43 | done 44 | eval "${_fix_nullglob}" 45 | popd >> /dev/null 46 | -------------------------------------------------------------------------------- /test/tpl.bats.tpl: -------------------------------------------------------------------------------- 1 | % 2 | #!/usr/bin/env bash 3 | pushd test/tpl >> /dev/null 4 | exec > tpl.bats 5 | % 6 | # NOTE: BATS_TEST_DIRNAME => BASH_TPL_ROOT/test/tpl 7 | # 8 | 9 | setup() { 10 | bats_require_minimum_version 1.7.0 11 | load ../lib/diff 12 | # shellcheck source=../../bash-tpl 13 | source "${BATS_TEST_DIRNAME}/../../bash-tpl" 14 | } 15 | 16 | ## 17 | # test_template 18 | # $1 = template basename (no path) 19 | # Assumed to be relative to test/tpl 20 | # 21 | test_template() { 22 | pushd "${BATS_TEST_DIRNAME}" >> /dev/null 23 | local separate_stderr= 24 | # Does test include check for stderr? 25 | if [ -f "${BATS_TEST_DIRNAME}/${1%.tpl}.stderr" ]; then 26 | separate_stderr='--separate-stderr' 27 | fi 28 | run ${separate_stderr} -- main "${BATS_TEST_DIRNAME}/${1}" 29 | [[ $status = 0 ]] 30 | diff_output_file "${BATS_TEST_DIRNAME}/${1%.tpl}.sh" 31 | if [ "${output_type}" = "separate" ]; then 32 | diff_stderr_file "${BATS_TEST_DIRNAME}/${1%.tpl}.stderr" 33 | fi 34 | run bash "${BATS_TEST_DIRNAME}/${1%.tpl}.sh" 35 | diff_output_file "${BATS_TEST_DIRNAME}/${1%.tpl}.txt" 36 | popd >> /dev/null 37 | } 38 | % _fix_nullglob=$(shopt -p nullglob || true) 39 | % shopt -s nullglob 40 | % for tpl in *.tpl; do 41 | %# blank space below is intentional 42 | 43 | @test "tpl: Should render test/tpl/<% $tpl %> to match test/tpl/<%"${tpl%.tpl}.sh"%> { 44 | test_template "<% $tpl %>" 45 | } 46 | % done 47 | % eval "${_fix_nullglob}" 48 | % popd >> /dev/null 49 | -------------------------------------------------------------------------------- /test/tpl/complex_text.sh: -------------------------------------------------------------------------------- 1 | printf "%b%s%b%s%b%s\n" 'Plain text, ' "$TAG" ', ' " QUOTE TAG " ', ' "$(echo "SCRIPT TAG")" 2 | -------------------------------------------------------------------------------- /test/tpl/complex_text.tpl: -------------------------------------------------------------------------------- 1 | Plain text, <% $TAG %>, <%" QUOTE TAG "%>, <%% echo "SCRIPT TAG" %> 2 | -------------------------------------------------------------------------------- /test/tpl/complex_text.txt: -------------------------------------------------------------------------------- 1 | Plain text, , QUOTE TAG , SCRIPT TAG 2 | -------------------------------------------------------------------------------- /test/tpl/formatted_text.sh: -------------------------------------------------------------------------------- 1 | myint=100 2 | myintfmt='%d' 3 | mydec=3.14159 4 | mydecfmt='%f' 5 | mystr='one\ttwo' 6 | printf "\n" 7 | printf "%s\n" "$myint" 8 | printf "%s\n" "$myint" 9 | printf "%d\n" "$myint" 10 | printf "%d\n" "$myint" 11 | printf "${myintfmt}\n" "$myint" 12 | printf "%5d\n" "$myint" 13 | printf "%05d\n" "$myint" 14 | printf "%x\n" "$myint" 15 | printf "\n" 16 | printf "%s\n" "$mydec" 17 | printf "%s\n" "$mydec" 18 | printf "%f\n" "$mydec" 19 | printf "%f\n" "$mydec" 20 | printf "${mydecfmt}\n" "$mydec" 21 | printf "%.2f\n" "$mydec" 22 | printf "%07.2f\n" "$mydec" 23 | printf "\n" 24 | printf "%s\n" "$mystr" 25 | printf "%s\n" "$mystr" 26 | printf "%s\n" "$mystr" 27 | printf "%s\n" "$mystr" 28 | printf "%20s%b\n" "$mystr" '.' 29 | printf "%-20s%b\n" "$mystr" '.' 30 | printf "%b\n" "$mystr" 31 | printf "\n" 32 | printf "%b%b%b\n" '.' " $mystr " '.' 33 | printf "%b\n" "$(echo $mystr)" 34 | printf "\n" 35 | printf "\n" 36 | printf "%s\n" "$myint" 37 | printf "%s\n" "$myint" 38 | printf "%d\n" "$myint" 39 | printf "%d\n" "$myint" 40 | printf "${myintfmt}\n" "$myint" 41 | printf "%5d\n" "$myint" 42 | printf "%05d\n" "$myint" 43 | printf "%x\n" "$myint" 44 | printf "\n" 45 | printf "%s\n" "$mydec" 46 | printf "%s\n" "$mydec" 47 | printf "%f\n" "$mydec" 48 | printf "%f\n" "$mydec" 49 | printf "${mydecfmt}\n" "$mydec" 50 | printf "%.2f\n" "$mydec" 51 | printf "%07.2f\n" "$mydec" 52 | printf "\n" 53 | printf "%s\n" "$mystr" 54 | printf "%s\n" "$mystr" 55 | printf "%s\n" "$mystr" 56 | printf "%s\n" "$mystr" 57 | printf "%20s%b\n" "$mystr" '.' 58 | printf "%-20s%b\n" "$mystr" '.' 59 | printf "%b\n" "$mystr" 60 | printf "\n" 61 | printf "%b%b%b\n" '.' " $mystr " '.' 62 | printf "%b\n" "$(echo $mystr)" 63 | -------------------------------------------------------------------------------- /test/tpl/formatted_text.tpl: -------------------------------------------------------------------------------- 1 | % myint=100 2 | % myintfmt='%d' 3 | % mydec=3.14159 4 | % mydecfmt='%f' 5 | % mystr='one\ttwo' 6 | 7 | <%$myint%> 8 | <%||$myint%> 9 | <% | %d | $myint%> 10 | <%|%d|$myint%> 11 | <%|${myintfmt}|$myint%> 12 | <%|%5d|$myint%> 13 | <%|%05d|$myint%> 14 | <%|%x|$myint%> 15 | 16 | <%$mydec%> 17 | <%||$mydec%> 18 | <% | %f | $mydec%> 19 | <%|%f|$mydec%> 20 | <%|${mydecfmt}|$mydec%> 21 | <%|%.2f|$mydec%> 22 | <%|%07.2f|$mydec%> 23 | 24 | <%$mystr%> 25 | <%||$mystr%> 26 | <% | %s | $mystr%> 27 | <%|%s|$mystr%> 28 | <%|%20s|$mystr%>. 29 | <%|%-20s|$mystr%>. 30 | <%|%b|$mystr%> 31 | 32 | .<% | %b | " $mystr " %>. 33 | <%|%b|% echo $mystr%> 34 | 35 | .DELIMS tag="{{ }}" tag-fmt="[ ]" 36 | 37 | {{$myint}} 38 | {{[]$myint}} 39 | {{ [ %d ] $myint}} 40 | {{[%d]$myint}} 41 | {{[${myintfmt}]$myint}} 42 | {{[%5d]$myint}} 43 | {{[%05d]$myint}} 44 | {{[%x]$myint}} 45 | 46 | {{$mydec}} 47 | {{[]$mydec}} 48 | {{ [ %f ] $mydec}} 49 | {{[%f]$mydec}} 50 | {{[${mydecfmt}]$mydec}} 51 | {{[%.2f]$mydec}} 52 | {{[%07.2f]$mydec}} 53 | 54 | {{$mystr}} 55 | {{[]$mystr}} 56 | {{ [ %s ] $mystr}} 57 | {{[%s]$mystr}} 58 | {{[%20s]$mystr}}. 59 | {{[%-20s]$mystr}}. 60 | {{[%b]$mystr}} 61 | 62 | .{{ [ %b ] " $mystr " }}. 63 | {{[%b]% echo $mystr}} 64 | -------------------------------------------------------------------------------- /test/tpl/formatted_text.txt: -------------------------------------------------------------------------------- 1 | 2 | 100 3 | 100 4 | 100 5 | 100 6 | 100 7 | 100 8 | 00100 9 | 64 10 | 11 | 3.14159 12 | 3.14159 13 | 3.141590 14 | 3.141590 15 | 3.141590 16 | 3.14 17 | 0003.14 18 | 19 | one\ttwo 20 | one\ttwo 21 | one\ttwo 22 | one\ttwo 23 | one\ttwo. 24 | one\ttwo . 25 | one two 26 | 27 | . one two . 28 | one two 29 | 30 | 31 | 100 32 | 100 33 | 100 34 | 100 35 | 100 36 | 100 37 | 00100 38 | 64 39 | 40 | 3.14159 41 | 3.14159 42 | 3.141590 43 | 3.141590 44 | 3.141590 45 | 3.14 46 | 0003.14 47 | 48 | one\ttwo 49 | one\ttwo 50 | one\ttwo 51 | one\ttwo 52 | one\ttwo. 53 | one\ttwo . 54 | one two 55 | 56 | . one two . 57 | one two 58 | -------------------------------------------------------------------------------- /test/tpl/hello_world.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" 'Hello, world' 2 | -------------------------------------------------------------------------------- /test/tpl/hello_world.tpl: -------------------------------------------------------------------------------- 1 | Hello, world 2 | -------------------------------------------------------------------------------- /test/tpl/hello_world.txt: -------------------------------------------------------------------------------- 1 | Hello, world 2 | -------------------------------------------------------------------------------- /test/tpl/include_missing_err.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" 'before' 2 | printf "%b\n" 'after' 3 | -------------------------------------------------------------------------------- /test/tpl/include_missing_err.stderr: -------------------------------------------------------------------------------- 1 | File not found: 'not_found.tpl' 2 | -------------------------------------------------------------------------------- /test/tpl/include_missing_err.tpl: -------------------------------------------------------------------------------- 1 | before 2 | .INCLUDE not_found.tpl 3 | after 4 | -------------------------------------------------------------------------------- /test/tpl/include_missing_err.txt: -------------------------------------------------------------------------------- 1 | before 2 | after 3 | -------------------------------------------------------------------------------- /test/tpl/include_missing_ok.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" 'before' 2 | printf "%b\n" 'after' 3 | -------------------------------------------------------------------------------- /test/tpl/include_missing_ok.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TekWizely/bash-tpl/0a9e3eddfa38842ae63545e0c629794be687e19f/test/tpl/include_missing_ok.stderr -------------------------------------------------------------------------------- /test/tpl/include_missing_ok.tpl: -------------------------------------------------------------------------------- 1 | before 2 | .INCLUDE? not_found.tpl 3 | after 4 | -------------------------------------------------------------------------------- /test/tpl/include_missing_ok.txt: -------------------------------------------------------------------------------- 1 | before 2 | after 3 | -------------------------------------------------------------------------------- /test/tpl/include_simple.inc: -------------------------------------------------------------------------------- 1 | Hello, world 2 | -------------------------------------------------------------------------------- /test/tpl/include_simple.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" 'Hello, world' 2 | -------------------------------------------------------------------------------- /test/tpl/include_simple.tpl: -------------------------------------------------------------------------------- 1 | .INCLUDE hello_world.tpl 2 | -------------------------------------------------------------------------------- /test/tpl/include_simple.txt: -------------------------------------------------------------------------------- 1 | Hello, world 2 | -------------------------------------------------------------------------------- /test/tpl/include_undent.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" 'Hello, world' 2 | printf "%b\n" '\tHello, world' 3 | # L1 4 | printf "%b\n" 'Hello, world' 5 | # L2 6 | printf "%b\n" 'Hello, world' 7 | # /L2 8 | printf "%b\n" 'Hello, world' 9 | # /L1 10 | # L1 11 | printf "%b\n" '\tHello, world' 12 | # L2 13 | printf "%b\n" '\tHello, world' 14 | # /L2 15 | printf "%b\n" '\tHello, world' 16 | printf "%b\n" 'Hello, world' 17 | # /L1 18 | printf "%b\n" 'Hello, world' 19 | printf "%b\n" '\tHello, world' 20 | # L2 21 | printf "%b\n" '\tHello, world' 22 | # /L2 23 | printf "%b\n" 'Hello, world' 24 | -------------------------------------------------------------------------------- /test/tpl/include_undent.tpl: -------------------------------------------------------------------------------- 1 | .INCLUDE hello_world.tpl 2 | .INCLUDE hello_world.tpl 3 | % # L1 4 | .INCLUDE hello_world.tpl 5 | % # L2 6 | .INCLUDE hello_world.tpl 7 | % # /L2 8 | .INCLUDE hello_world.tpl 9 | % # /L1 10 | % # L1 11 | .INCLUDE hello_world.tpl 12 | % # L2 13 | .INCLUDE hello_world.tpl 14 | % # /L2 15 | .INCLUDE hello_world.tpl 16 | .INCLUDE hello_world.tpl 17 | % # /L1 18 | .INCLUDE hello_world.tpl 19 | .INCLUDE hello_world.tpl 20 | % # L2 21 | .INCLUDE hello_world.tpl 22 | % # /L2 23 | .INCLUDE hello_world.tpl 24 | -------------------------------------------------------------------------------- /test/tpl/include_undent.txt: -------------------------------------------------------------------------------- 1 | Hello, world 2 | Hello, world 3 | Hello, world 4 | Hello, world 5 | Hello, world 6 | Hello, world 7 | Hello, world 8 | Hello, world 9 | Hello, world 10 | Hello, world 11 | Hello, world 12 | Hello, world 13 | Hello, world 14 | -------------------------------------------------------------------------------- /test/tpl/regression01.sh: -------------------------------------------------------------------------------- 1 | # 1 2 | # 2 3 | printf "%b\n" '3' 4 | # 4 5 | # 5 6 | printf "%b\n" '6' 7 | # 7 8 | -------------------------------------------------------------------------------- /test/tpl/regression01.tpl: -------------------------------------------------------------------------------- 1 | % # 1 2 | % # 2 3 | 3 4 | % # 4 5 | % # 5 6 | 6 7 | % # 7 8 | -------------------------------------------------------------------------------- /test/tpl/regression01.txt: -------------------------------------------------------------------------------- 1 | 3 2 | 6 3 | -------------------------------------------------------------------------------- /test/tpl/script_block.sh: -------------------------------------------------------------------------------- 1 | echo "Block line 1.1" 2 | echo "Block line 1.2" 3 | echo "Block line 1.1.1" 4 | echo "Block line 1.2.1" 5 | echo "Block line 2.1" 6 | echo "Block line 2.2" 7 | echo "Block line 2.3" 8 | echo "Block line 2.4" 9 | echo "Block line 2.5" 10 | echo "Block line 2.6" 11 | echo "Block line 2.1.1" 12 | echo "Block line 2.2.1" 13 | echo "Block line 2.3.1" 14 | echo "Block line 2.4.1" 15 | echo "Block line 2.5.1" 16 | echo "Block line 2.6.1" 17 | echo "Block line 3.1" 18 | echo "Block line 3.2" 19 | echo "Block line 3.1.1" 20 | echo "Block line 3.2.1" 21 | echo "Block line 4.1" 22 | echo "Block line 4.2" 23 | echo "Block line 4.3" 24 | echo "Block line 4.4" 25 | echo "Block line 4.5" 26 | echo "Block line 4.6" 27 | echo "Block line 4.7" 28 | echo "Block line 4.8" 29 | echo "Block line 4.9" 30 | echo "Block line 4.10" 31 | echo "Block line 4.3.1" 32 | echo "Block line 4.4.1" 33 | echo "Block line 4.6.1" 34 | echo "Block line 4.8.1" 35 | -------------------------------------------------------------------------------- /test/tpl/script_block.tpl: -------------------------------------------------------------------------------- 1 | % 2 | % 3 | % 4 | echo "Block line 1.1" 5 | echo "Block line 1.2" 6 | % 7 | % 8 | echo "Block line 1.1.1" 9 | echo "Block line 1.2.1" 10 | % 11 | % 12 | echo "Block line 2.1" 13 | echo "Block line 2.2" 14 | echo "Block line 2.3" 15 | echo "Block line 2.4" 16 | echo "Block line 2.5" 17 | echo "Block line 2.6" 18 | % 19 | % 20 | echo "Block line 2.1.1" 21 | echo "Block line 2.2.1" 22 | echo "Block line 2.3.1" 23 | echo "Block line 2.4.1" 24 | echo "Block line 2.5.1" 25 | echo "Block line 2.6.1" 26 | % 27 | % 28 | echo "Block line 3.1" 29 | echo "Block line 3.2" 30 | % 31 | % 32 | echo "Block line 3.1.1" 33 | echo "Block line 3.2.1" 34 | % 35 | % 36 | echo "Block line 4.1" 37 | echo "Block line 4.2" 38 | echo "Block line 4.3" 39 | echo "Block line 4.4" 40 | echo "Block line 4.5" 41 | echo "Block line 4.6" 42 | echo "Block line 4.7" 43 | echo "Block line 4.8" 44 | echo "Block line 4.9" 45 | echo "Block line 4.10" 46 | % 47 | % 48 | echo "Block line 4.3.1" 49 | echo "Block line 4.4.1" 50 | echo "Block line 4.6.1" 51 | echo "Block line 4.8.1" 52 | % 53 | -------------------------------------------------------------------------------- /test/tpl/script_block.txt: -------------------------------------------------------------------------------- 1 | Block line 1.1 2 | Block line 1.2 3 | Block line 1.1.1 4 | Block line 1.2.1 5 | Block line 2.1 6 | Block line 2.2 7 | Block line 2.3 8 | Block line 2.4 9 | Block line 2.5 10 | Block line 2.6 11 | Block line 2.1.1 12 | Block line 2.2.1 13 | Block line 2.3.1 14 | Block line 2.4.1 15 | Block line 2.5.1 16 | Block line 2.6.1 17 | Block line 3.1 18 | Block line 3.2 19 | Block line 3.1.1 20 | Block line 3.2.1 21 | Block line 4.1 22 | Block line 4.2 23 | Block line 4.3 24 | Block line 4.4 25 | Block line 4.5 26 | Block line 4.6 27 | Block line 4.7 28 | Block line 4.8 29 | Block line 4.9 30 | Block line 4.10 31 | Block line 4.3.1 32 | Block line 4.4.1 33 | Block line 4.6.1 34 | Block line 4.8.1 35 | -------------------------------------------------------------------------------- /test/tpl/script_block_text.sh: -------------------------------------------------------------------------------- 1 | echo "Block line 1.1" 2 | printf "%b\n" 'Block text line 1.2' 3 | echo "Block line 1.1.1" 4 | printf "%b\n" 'Block text line 1.2.1' 5 | echo "Block line 2.1" 6 | printf "%b\n" 'Block text line 2.2' 7 | echo "Block line 2.3" 8 | printf "%b\n" 'Block text line 2.4' 9 | echo "Block line 2.5" 10 | printf "%b\n" 'Block text line 2.6' 11 | echo "Block line 2.7" 12 | printf "%b\n" 'Block text line 2.8' 13 | echo "Block line 2.1.1" 14 | printf "%b\n" 'Block text line 2.2.1' 15 | echo "Block line 2.3.1" 16 | printf "%b\n" 'Block text line 2.4.1' 17 | echo "Block line 2.5.1" 18 | printf "%b\n" 'Block text line 2.6.1' 19 | echo "Block line 2.7.1" 20 | printf "%b\n" 'Block text line 2.8.1' 21 | echo "Block line 3.1" 22 | printf "%b\n" ' Block text line 3.2' 23 | echo "Block line 3.1.1" 24 | printf "%b\n" ' Block text line 3.2.1' 25 | echo "Block line 4.1" 26 | printf "%b\n" 'Block text line 4.2' 27 | echo "Block line 4.3" 28 | printf "%b\n" 'Block text line 4.4' 29 | echo "Block line 4.5" 30 | printf "%b\n" 'Block text line 4.6' 31 | echo "Block line 4.7" 32 | printf "%b\n" 'Block text line 4.8' 33 | echo "Block line 4.9" 34 | printf "%b\n" 'Block text line 4.10' 35 | echo "Block line 4.11" 36 | printf "%b\n" 'Block text line 4.12' 37 | printf "%b\n" 'Block text line 5.1' 38 | echo "Block line 5.2" 39 | printf "%b\n" 'Block text line 5.1.1' 40 | echo "Block line 5.2.1" 41 | printf "%b\n" 'Block text line 6.1' 42 | echo "Block line 6.2" 43 | printf "%b\n" 'Block text line 6.3' 44 | echo "Block line 6.4" 45 | printf "%b\n" 'Block text line 6.5' 46 | echo "Block line 6.6" 47 | printf "%b\n" 'Block text line 6.7' 48 | echo "Block line 6.8" 49 | printf "%b\n" ' Block text line 7.1' 50 | echo "Block line 7.2" 51 | printf "%b\n" ' Block text line 7.1.1' 52 | echo "Block line 7.2.1" 53 | printf "%b\n" 'Block text line 8.1' 54 | echo "Block line 8.2" 55 | printf "%b\n" 'Block text line 8.3' 56 | echo "Block line 8.4" 57 | printf "%b\n" 'Block text line 8.5' 58 | echo "Block line 8.6" 59 | printf "%b\n" 'Block text line 8.7' 60 | echo "Block line 8.8" 61 | printf "%b\n" 'Block text line 8.9' 62 | echo "Block line 8.10" 63 | printf "%b\n" 'Block text line 8.11' 64 | echo "Block line 8.12" 65 | -------------------------------------------------------------------------------- /test/tpl/script_block_text.tpl: -------------------------------------------------------------------------------- 1 | % 2 | echo "Block line 1.1" 3 | % Block text line 1.2 4 | % 5 | % 6 | echo "Block line 1.1.1" 7 | % Block text line 1.2.1 8 | % 9 | % 10 | echo "Block line 2.1" 11 | % Block text line 2.2 12 | echo "Block line 2.3" 13 | % Block text line 2.4 14 | echo "Block line 2.5" 15 | % Block text line 2.6 16 | echo "Block line 2.7" 17 | % Block text line 2.8 18 | % 19 | % 20 | echo "Block line 2.1.1" 21 | % Block text line 2.2.1 22 | echo "Block line 2.3.1" 23 | % Block text line 2.4.1 24 | echo "Block line 2.5.1" 25 | % Block text line 2.6.1 26 | echo "Block line 2.7.1" 27 | % Block text line 2.8.1 28 | % 29 | % 30 | echo "Block line 3.1" 31 | % Block text line 3.2 32 | % 33 | % 34 | echo "Block line 3.1.1" 35 | % Block text line 3.2.1 36 | % 37 | % 38 | echo "Block line 4.1" 39 | % Block text line 4.2 40 | echo "Block line 4.3" 41 | % Block text line 4.4 42 | echo "Block line 4.5" 43 | % Block text line 4.6 44 | echo "Block line 4.7" 45 | % Block text line 4.8 46 | echo "Block line 4.9" 47 | % Block text line 4.10 48 | echo "Block line 4.11" 49 | % Block text line 4.12 50 | % 51 | % 52 | % Block text line 5.1 53 | echo "Block line 5.2" 54 | % 55 | % 56 | % Block text line 5.1.1 57 | echo "Block line 5.2.1" 58 | % 59 | % 60 | % Block text line 6.1 61 | echo "Block line 6.2" 62 | % Block text line 6.3 63 | echo "Block line 6.4" 64 | % Block text line 6.5 65 | echo "Block line 6.6" 66 | % Block text line 6.7 67 | echo "Block line 6.8" 68 | % 69 | % 70 | % Block text line 7.1 71 | echo "Block line 7.2" 72 | % 73 | % 74 | % Block text line 7.1.1 75 | echo "Block line 7.2.1" 76 | % 77 | % 78 | % Block text line 8.1 79 | echo "Block line 8.2" 80 | % Block text line 8.3 81 | echo "Block line 8.4" 82 | % Block text line 8.5 83 | echo "Block line 8.6" 84 | % Block text line 8.7 85 | echo "Block line 8.8" 86 | % Block text line 8.9 87 | echo "Block line 8.10" 88 | % Block text line 8.11 89 | echo "Block line 8.12" 90 | % 91 | -------------------------------------------------------------------------------- /test/tpl/script_block_text.txt: -------------------------------------------------------------------------------- 1 | Block line 1.1 2 | Block text line 1.2 3 | Block line 1.1.1 4 | Block text line 1.2.1 5 | Block line 2.1 6 | Block text line 2.2 7 | Block line 2.3 8 | Block text line 2.4 9 | Block line 2.5 10 | Block text line 2.6 11 | Block line 2.7 12 | Block text line 2.8 13 | Block line 2.1.1 14 | Block text line 2.2.1 15 | Block line 2.3.1 16 | Block text line 2.4.1 17 | Block line 2.5.1 18 | Block text line 2.6.1 19 | Block line 2.7.1 20 | Block text line 2.8.1 21 | Block line 3.1 22 | Block text line 3.2 23 | Block line 3.1.1 24 | Block text line 3.2.1 25 | Block line 4.1 26 | Block text line 4.2 27 | Block line 4.3 28 | Block text line 4.4 29 | Block line 4.5 30 | Block text line 4.6 31 | Block line 4.7 32 | Block text line 4.8 33 | Block line 4.9 34 | Block text line 4.10 35 | Block line 4.11 36 | Block text line 4.12 37 | Block text line 5.1 38 | Block line 5.2 39 | Block text line 5.1.1 40 | Block line 5.2.1 41 | Block text line 6.1 42 | Block line 6.2 43 | Block text line 6.3 44 | Block line 6.4 45 | Block text line 6.5 46 | Block line 6.6 47 | Block text line 6.7 48 | Block line 6.8 49 | Block text line 7.1 50 | Block line 7.2 51 | Block text line 7.1.1 52 | Block line 7.2.1 53 | Block text line 8.1 54 | Block line 8.2 55 | Block text line 8.3 56 | Block line 8.4 57 | Block text line 8.5 58 | Block line 8.6 59 | Block text line 8.7 60 | Block line 8.8 61 | Block text line 8.9 62 | Block line 8.10 63 | Block text line 8.11 64 | Block line 8.12 65 | -------------------------------------------------------------------------------- /test/tpl/script_tag.sh: -------------------------------------------------------------------------------- 1 | # Script comment should be rendered 2 | echo "Script Tag" 3 | -------------------------------------------------------------------------------- /test/tpl/script_tag.tpl: -------------------------------------------------------------------------------- 1 | % # Script comment should be rendered 2 | % echo "Script Tag" 3 | -------------------------------------------------------------------------------- /test/tpl/script_tag.txt: -------------------------------------------------------------------------------- 1 | Script Tag 2 | -------------------------------------------------------------------------------- /test/tpl/script_tag_indent.sh: -------------------------------------------------------------------------------- 1 | # Indented text should be undented 2 | if true; then 3 | printf "%b\n" 'Text1' 4 | else 5 | printf "%b\n" 'Text2' 6 | fi 7 | printf "%b\n" ' Text3' 8 | -------------------------------------------------------------------------------- /test/tpl/script_tag_indent.tpl: -------------------------------------------------------------------------------- 1 | % # Indented text should be undented 2 | % if true; then 3 | Text1 4 | % else 5 | Text2 6 | % fi 7 | Text3 8 | -------------------------------------------------------------------------------- /test/tpl/script_tag_indent.txt: -------------------------------------------------------------------------------- 1 | Text1 2 | Text3 3 | -------------------------------------------------------------------------------- /test/tpl/text_with_dollar.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" '$Hello' 2 | printf "%b\n" '<$Hello' 3 | printf "%b%b\n" '<' '%$Hello' 4 | printf "%b%b\n" '<' '<$Hello' 5 | printf "%b\n" '%$Hello' 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_dollar.tpl: -------------------------------------------------------------------------------- 1 | $Hello 2 | <$Hello 3 | <%$Hello 4 | <<$Hello 5 | %$Hello 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_dollar.txt: -------------------------------------------------------------------------------- 1 | $Hello 2 | <$Hello 3 | <%$Hello 4 | <<$Hello 5 | %$Hello 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_escapes.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" '\\tHello' 2 | printf "%b\n" '<\\tHello' 3 | printf "%b%b\n" '<' '%\\tHello' 4 | printf "%b%b\n" '<' '<\\tHello' 5 | printf "%b\n" '%\\tHello' 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_escapes.tpl: -------------------------------------------------------------------------------- 1 | \tHello 2 | <\tHello 3 | <%\tHello 4 | <<\tHello 5 | %\tHello 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_escapes.txt: -------------------------------------------------------------------------------- 1 | \tHello 2 | <\tHello 3 | <%\tHello 4 | <<\tHello 5 | %\tHello 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_quotes.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" '\0047Hello' 2 | printf "%b\n" '<\0047Hello' 3 | printf "%b%b\n" '<' '%\0047Hello' 4 | printf "%b%b\n" '<' '<\0047Hello' 5 | printf "%b\n" '%\0047Hello' 6 | printf "%b\n" '"Hello' 7 | printf "%b\n" '<"Hello' 8 | printf "%b%b\n" '<' '%"Hello' 9 | printf "%b%b\n" '<' '<"Hello' 10 | printf "%b\n" '%"Hello' 11 | printf "%b\n" 'Hello \0047World\0047' 12 | printf "%b\n" 'Hello "World"' 13 | -------------------------------------------------------------------------------- /test/tpl/text_with_quotes.tpl: -------------------------------------------------------------------------------- 1 | 'Hello 2 | <'Hello 3 | <%'Hello 4 | <<'Hello 5 | %'Hello 6 | "Hello 7 | <"Hello 8 | <%"Hello 9 | <<"Hello 10 | %"Hello 11 | Hello 'World' 12 | Hello "World" 13 | -------------------------------------------------------------------------------- /test/tpl/text_with_quotes.txt: -------------------------------------------------------------------------------- 1 | 'Hello 2 | <'Hello 3 | <%'Hello 4 | <<'Hello 5 | %'Hello 6 | "Hello 7 | <"Hello 8 | <%"Hello 9 | <<"Hello 10 | %"Hello 11 | Hello 'World' 12 | Hello "World" 13 | -------------------------------------------------------------------------------- /test/tpl/text_with_tabs.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" '\tHello' 2 | printf "%b\n" '<\tHello' 3 | printf "%b%b\n" '<' '%\tHello' 4 | printf "%b%b\n" '<' '<\tHello' 5 | echo Hello 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_tabs.tpl: -------------------------------------------------------------------------------- 1 | Hello 2 | < Hello 3 | <% Hello 4 | << Hello 5 | % echo Hello 6 | -------------------------------------------------------------------------------- /test/tpl/text_with_tabs.txt: -------------------------------------------------------------------------------- 1 | Hello 2 | < Hello 3 | <% Hello 4 | << Hello 5 | Hello 6 | -------------------------------------------------------------------------------- /test/tpl/tpl_comment.sh: -------------------------------------------------------------------------------- 1 | printf "%b\n" 'Hello, world' 2 | -------------------------------------------------------------------------------- /test/tpl/tpl_comment.tpl: -------------------------------------------------------------------------------- 1 | %# This comment should not be rendered 2 | Hello, world 3 | %# This comment should also not be rendered 4 | -------------------------------------------------------------------------------- /test/tpl/tpl_comment.txt: -------------------------------------------------------------------------------- 1 | Hello, world 2 | -------------------------------------------------------------------------------- /test/tpl/var_with_escapes.sh: -------------------------------------------------------------------------------- 1 | myvar="\tHello\nWorld" 2 | printf "%s\n" "$myvar" 3 | -------------------------------------------------------------------------------- /test/tpl/var_with_escapes.tpl: -------------------------------------------------------------------------------- 1 | % myvar="\tHello\nWorld" 2 | <% $myvar %> 3 | -------------------------------------------------------------------------------- /test/tpl/var_with_escapes.txt: -------------------------------------------------------------------------------- 1 | \tHello\nWorld 2 | --------------------------------------------------------------------------------