1# Automatically generated from specification file: 'inverted.json'
2#
3# Inverted Section tags and End Section tags are used in combination to wrap a
4# section of the template.
5#
6# These tags' content MUST be a non-whitespace character sequence NOT
7# containing the current closing delimiter; each Inverted Section tag MUST be
8# followed by an End Section tag with the same content within the same
9# section.
10#
11# This tag's content names the data to replace�the tag.  Name resolution is as
12# follows:
13#   1) Split the name on periods; the first part is the name to resolve, any
14#   remaining parts should be retained.
15#   2) Walk the context stack from top to bottom, finding the first context
16#   that is a) a hash containing the name as a key OR b) an object responding
17#   to a method with the given name.
18#   3) If the context is a hash, the data is the value associated with the
19#   name.
20#   4) If the context is an object and the method with the given name has an
21#   arity of 1, the method SHOULD be called with a String containing the
22#   unprocessed contents of the sections; the data is the value returned.
23#   5) Otherwise, the data is the value returned by calling the method with
24#   the given name.
25#   6) If any name parts were retained in step 1, each should be resolved
26#   against a context stack containing only the result from the former
27#   resolution.  If any part fails resolution, the result should be considered
28#   falsey, and should interpolate as the empty string.
29# If the data is not of a list type, it is coerced into a list as follows: if
30# the data is truthy (e.g. `!!data == true`), use a single-element list
31# containing the data, otherwise use an empty list.
32#
33# This section MUST NOT be rendered unless the data list is empty.
34#
35# Inverted Section and End Section tags SHOULD be treated as standalone when
36# appropriate.
37#
38library(testthat)
39context('Spec v1.1, inverted')
40
41test_that( "Falsey", {
42  #"Falsey sections should have their contents rendered."
43  template <- "\"{{^boolean}}This should be rendered.{{/boolean}}\""
44  data <- list(boolean = FALSE)
45
46
47  str <- whisker.render(template, data=data)
48
49  expect_equal(str, "\"This should be rendered.\"", label=deparse(str), info="Falsey sections should have their contents rendered.")
50})
51
52test_that( "Truthy", {
53  #"Truthy sections should have their contents omitted."
54  template <- "\"{{^boolean}}This should not be rendered.{{/boolean}}\""
55  data <- list(boolean = TRUE)
56
57
58  str <- whisker.render(template, data=data)
59
60  expect_equal(str, "\"\"", label=deparse(str), info="Truthy sections should have their contents omitted.")
61})
62
63test_that( "Context", {
64  #"Objects and hashes should behave like truthy values."
65  template <- "\"{{^context}}Hi {{name}}.{{/context}}\""
66  data <- list(context = list(name = "Joe"))
67
68
69  str <- whisker.render(template, data=data)
70
71  expect_equal(str, "\"\"", label=deparse(str), info="Objects and hashes should behave like truthy values.")
72})
73
74test_that( "List", {
75  #"Lists should behave like truthy values."
76  template <- "\"{{^list}}{{n}}{{/list}}\""
77  data <- list(list = list(list(n = 1), list(n = 2), list(n = 3)))
78
79
80  str <- whisker.render(template, data=data)
81
82  expect_equal(str, "\"\"", label=deparse(str), info="Lists should behave like truthy values.")
83})
84
85test_that( "Empty List", {
86  #"Empty lists should behave like falsey values."
87  template <- "\"{{^list}}Yay lists!{{/list}}\""
88  data <- list(list = list())
89
90
91  str <- whisker.render(template, data=data)
92
93  expect_equal(str, "\"Yay lists!\"", label=deparse(str), info="Empty lists should behave like falsey values.")
94})
95
96test_that( "Doubled", {
97  #"Multiple inverted sections per template should be permitted."
98  template <- "{{^bool}}\n* first\n{{/bool}}\n* {{two}}\n{{^bool}}\n* third\n{{/bool}}\n"
99  data <- list(two = "second", bool = FALSE)
100
101
102  str <- whisker.render(template, data=data)
103
104  expect_equal(str, "* first\n* second\n* third\n", label=deparse(str), info="Multiple inverted sections per template should be permitted.")
105})
106
107test_that( "Nested (Falsey)", {
108  #"Nested falsey sections should have their contents rendered."
109  template <- "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"
110  data <- list(bool = FALSE)
111
112
113  str <- whisker.render(template, data=data)
114
115  expect_equal(str, "| A B C D E |", label=deparse(str), info="Nested falsey sections should have their contents rendered.")
116})
117
118test_that( "Nested (Truthy)", {
119  #"Nested truthy sections should be omitted."
120  template <- "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"
121  data <- list(bool = TRUE)
122
123
124  str <- whisker.render(template, data=data)
125
126  expect_equal(str, "| A  E |", label=deparse(str), info="Nested truthy sections should be omitted.")
127})
128
129test_that( "Context Misses", {
130  #"Failed context lookups should be considered falsey."
131  template <- "[{{^missing}}Cannot find key 'missing'!{{/missing}}]"
132  data <- list()
133
134
135  str <- whisker.render(template, data=data)
136
137  expect_equal(str, "[Cannot find key 'missing'!]", label=deparse(str), info="Failed context lookups should be considered falsey.")
138})
139
140test_that( "Dotted Names - Truthy", {
141  #"Dotted names should be valid for Inverted Section tags."
142  template <- "\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"\""
143  data <- list(a = list(b = list(c = TRUE)))
144
145
146  str <- whisker.render(template, data=data)
147
148  expect_equal(str, "\"\" == \"\"", label=deparse(str), info="Dotted names should be valid for Inverted Section tags.")
149})
150
151test_that( "Dotted Names - Falsey", {
152  #"Dotted names should be valid for Inverted Section tags."
153  template <- "\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\""
154  data <- list(a = list(b = list(c = FALSE)))
155
156
157  str <- whisker.render(template, data=data)
158
159  expect_equal(str, "\"Not Here\" == \"Not Here\"", label=deparse(str), info="Dotted names should be valid for Inverted Section tags.")
160})
161
162test_that( "Dotted Names - Broken Chains", {
163  #"Dotted names that cannot be resolved should be considered falsey."
164  template <- "\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\""
165  data <- list(a = list())
166
167
168  str <- whisker.render(template, data=data)
169
170  expect_equal(str, "\"Not Here\" == \"Not Here\"", label=deparse(str), info="Dotted names that cannot be resolved should be considered falsey.")
171})
172
173test_that( "Surrounding Whitespace", {
174  #"Inverted sections should not alter surrounding whitespace."
175  template <- " | {{^boolean}}\t|\t{{/boolean}} | \n"
176  data <- list(boolean = FALSE)
177
178
179  str <- whisker.render(template, data=data)
180
181  expect_equal(str, " | \t|\t | \n", label=deparse(str), info="Inverted sections should not alter surrounding whitespace.")
182})
183
184test_that( "Internal Whitespace", {
185  #"Inverted should not alter internal whitespace."
186  template <- " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"
187  data <- list(boolean = FALSE)
188
189
190  str <- whisker.render(template, data=data)
191
192  expect_equal(str, " |  \n  | \n", label=deparse(str), info="Inverted should not alter internal whitespace.")
193})
194
195test_that( "Indented Inline Sections", {
196  #"Single-line sections should not alter surrounding whitespace."
197  template <- " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n"
198  data <- list(boolean = FALSE)
199
200
201  str <- whisker.render(template, data=data)
202
203  expect_equal(str, " NO\n WAY\n", label=deparse(str), info="Single-line sections should not alter surrounding whitespace.")
204})
205
206test_that( "Standalone Lines", {
207  #"Standalone lines should be removed from the template."
208  template <- "| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n"
209  data <- list(boolean = FALSE)
210
211
212  str <- whisker.render(template, data=data)
213
214  expect_equal(str, "| This Is\n|\n| A Line\n", label=deparse(str), info="Standalone lines should be removed from the template.")
215})
216
217test_that( "Standalone Indented Lines", {
218  #"Standalone indented lines should be removed from the template."
219  template <- "| This Is\n  {{^boolean}}\n|\n  {{/boolean}}\n| A Line\n"
220  data <- list(boolean = FALSE)
221
222
223  str <- whisker.render(template, data=data)
224
225  expect_equal(str, "| This Is\n|\n| A Line\n", label=deparse(str), info="Standalone indented lines should be removed from the template.")
226})
227
228test_that( "Standalone Line Endings", {
229  #"\"\\r\\n\" should be considered a newline for standalone tags."
230  template <- "|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|"
231  data <- list(boolean = FALSE)
232
233
234  str <- whisker.render(template, data=data)
235
236  expect_equal(str, "|\r\n|", label=deparse(str), info="\"\\r\\n\" should be considered a newline for standalone tags.")
237})
238
239test_that( "Standalone Without Previous Line", {
240  #"Standalone tags should not require a newline to precede them."
241  template <- "  {{^boolean}}\n^{{/boolean}}\n/"
242  data <- list(boolean = FALSE)
243
244
245  str <- whisker.render(template, data=data)
246
247  expect_equal(str, "^\n/", label=deparse(str), info="Standalone tags should not require a newline to precede them.")
248})
249
250test_that( "Standalone Without Newline", {
251  #"Standalone tags should not require a newline to follow them."
252  template <- "^{{^boolean}}\n/\n  {{/boolean}}"
253  data <- list(boolean = FALSE)
254
255
256  str <- whisker.render(template, data=data)
257
258  expect_equal(str, "^\n/\n", label=deparse(str), info="Standalone tags should not require a newline to follow them.")
259})
260
261test_that( "Padding", {
262  #"Superfluous in-tag whitespace should be ignored."
263  template <- "|{{^ boolean }}={{/ boolean }}|"
264  data <- list(boolean = FALSE)
265
266
267  str <- whisker.render(template, data=data)
268
269  expect_equal(str, "|=|", label=deparse(str), info="Superfluous in-tag whitespace should be ignored.")
270})
271
272