/src/tests/Public/v6.0/GRMustacheRenderingObjectTest.m

https://github.com/oleganza/GRMustache · Objective C · 757 lines · 663 code · 64 blank · 30 comment · 12 complexity · b74eefc4fe77d77276706b6c5932e0b6 MD5 · raw file

  1. // The MIT License
  2. //
  3. // Copyright (c) 2013 Gwendal Roué
  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
  13. // all 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
  21. // THE SOFTWARE.
  22. #define GRMUSTACHE_VERSION_MAX_ALLOWED GRMUSTACHE_VERSION_6_0
  23. #import "GRMustachePublicAPITest.h"
  24. @interface GRMustacheRenderingObjectTest : GRMustachePublicAPITest
  25. @end
  26. @interface GRMustacheAttributedSectionTagHelper : NSObject<GRMustacheRendering> {
  27. NSString *_attribute;
  28. }
  29. @property (nonatomic, copy) NSString *attribute;
  30. @end
  31. @implementation GRMustacheAttributedSectionTagHelper
  32. @synthesize attribute=_attribute;
  33. - (void)dealloc
  34. {
  35. self.attribute = nil;
  36. [super dealloc];
  37. }
  38. - (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error
  39. {
  40. GRMustacheTemplate *template = [tag.templateRepository templateFromString:@"attribute:{{attribute}}" error:NULL];
  41. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  42. }
  43. @end
  44. @implementation GRMustacheRenderingObjectTest
  45. - (void)testRenderingObjectPerformsVariableRendering
  46. {
  47. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  48. return @"---";
  49. }];
  50. NSDictionary *context = @{ @"object": object };
  51. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  52. STAssertEqualObjects(result, @"---", @"");
  53. }
  54. - (void)testRenderingObjectPerformsSectionRendering
  55. {
  56. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  57. return @"---";
  58. }];
  59. NSDictionary *context = @{ @"object": object };
  60. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:NULL];
  61. STAssertEqualObjects(result, @"---", @"");
  62. }
  63. - (void)testRenderingObjectPerformsInvertedSectionRendering
  64. {
  65. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  66. return @"---";
  67. }];
  68. NSDictionary *context = @{ @"object": object };
  69. NSString *result = [[GRMustacheTemplate templateFromString:@"{{^object}}{{/object}}" error:nil] renderObject:context error:NULL];
  70. STAssertEqualObjects(result, @"---", @"");
  71. }
  72. - (void)testRenderingObjectPerformsOverridableSectionRendering
  73. {
  74. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  75. return @"---";
  76. }];
  77. NSDictionary *context = @{ @"object": object };
  78. NSString *result = [[GRMustacheTemplate templateFromString:@"{{$object}}{{/object}}" error:nil] renderObject:context error:NULL];
  79. STAssertEqualObjects(result, @"---", @"");
  80. }
  81. - (void)testRenderingObjectPerformsHTMLSafeVariableRendering
  82. {
  83. {
  84. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  85. *HTMLSafe = YES;
  86. return @"&<>{{foo}}";
  87. }];
  88. NSDictionary *context = @{ @"object": object };
  89. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  90. STAssertEqualObjects(result, @"&<>{{foo}}", @"");
  91. }
  92. {
  93. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  94. *HTMLSafe = YES;
  95. return @"&<>{{foo}}";
  96. }];
  97. NSDictionary *context = @{ @"object": object };
  98. NSString *result = [[GRMustacheTemplate templateFromString:@"{{{object}}}" error:nil] renderObject:context error:NULL];
  99. STAssertEqualObjects(result, @"&<>{{foo}}", @"");
  100. }
  101. {
  102. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  103. *HTMLSafe = NO;
  104. return @"&<>{{foo}}";
  105. }];
  106. NSDictionary *context = @{ @"object": object };
  107. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  108. STAssertEqualObjects(result, @"&amp;&lt;&gt;{{foo}}", @"");
  109. }
  110. {
  111. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  112. *HTMLSafe = NO;
  113. return @"&<>{{foo}}";
  114. }];
  115. NSDictionary *context = @{ @"object": object };
  116. NSString *result = [[GRMustacheTemplate templateFromString:@"{{{object}}}" error:nil] renderObject:context error:NULL];
  117. STAssertEqualObjects(result, @"&<>{{foo}}", @"");
  118. }
  119. {
  120. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  121. // implicitly not safe
  122. return @"&<>{{foo}}";
  123. }];
  124. NSDictionary *context = @{ @"object": object };
  125. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  126. STAssertEqualObjects(result, @"&amp;&lt;&gt;{{foo}}", @"");
  127. }
  128. {
  129. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  130. // implicitly not safe
  131. return @"&<>{{foo}}";
  132. }];
  133. NSDictionary *context = @{ @"object": object };
  134. NSString *result = [[GRMustacheTemplate templateFromString:@"{{{object}}}" error:nil] renderObject:context error:NULL];
  135. STAssertEqualObjects(result, @"&<>{{foo}}", @"");
  136. }
  137. }
  138. - (void)testRenderingObjectPerformsHTMLSafeSectionRendering
  139. {
  140. {
  141. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  142. *HTMLSafe = YES;
  143. return @"&<>{{foo}}";
  144. }];
  145. NSDictionary *context = @{ @"object": object };
  146. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:NULL];
  147. STAssertEqualObjects(result, @"&<>{{foo}}", @"");
  148. }
  149. {
  150. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  151. *HTMLSafe = NO;
  152. return @"&<>{{foo}}";
  153. }];
  154. NSDictionary *context = @{ @"object": object };
  155. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:NULL];
  156. STAssertEqualObjects(result, @"&amp;&lt;&gt;{{foo}}", @"");
  157. }
  158. {
  159. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  160. // implicitly not safe
  161. return @"&<>{{foo}}";
  162. }];
  163. NSDictionary *context = @{ @"object": object };
  164. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:NULL];
  165. STAssertEqualObjects(result, @"&amp;&lt;&gt;{{foo}}", @"");
  166. }
  167. }
  168. - (void)testRenderingObjectCanSetError
  169. {
  170. {
  171. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  172. if (error) {
  173. *error = [NSError errorWithDomain:@"GRMustacheRenderingObjectDomain" code:-1 userInfo:nil];
  174. }
  175. return nil;
  176. }];
  177. NSError *error;
  178. NSDictionary *context = @{ @"object": object };
  179. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:&error];
  180. STAssertNil(result, @"");
  181. STAssertEqualObjects(error.domain, @"GRMustacheRenderingObjectDomain", @"");
  182. }
  183. {
  184. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  185. if (error) {
  186. *error = [NSError errorWithDomain:@"GRMustacheRenderingObjectDomain" code:-1 userInfo:nil];
  187. }
  188. return nil;
  189. }];
  190. NSError *error;
  191. NSDictionary *context = @{ @"object": object };
  192. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:&error];
  193. STAssertNil(result, @"");
  194. STAssertEqualObjects(error.domain, @"GRMustacheRenderingObjectDomain", @"");
  195. }
  196. }
  197. - (void)testRenderingObjectCanRenderNilWithoutSettingAnyError
  198. {
  199. {
  200. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  201. return nil;
  202. }];
  203. NSDictionary *context = @{ @"object": object };
  204. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  205. STAssertEqualObjects(result, @"", @"");
  206. }
  207. {
  208. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  209. return nil;
  210. }];
  211. NSDictionary *context = @{ @"object": object };
  212. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:NULL];
  213. STAssertEqualObjects(result, @"", @"");
  214. }
  215. }
  216. - (void)testRenderingObjectCanAccessTagType
  217. {
  218. __block NSUInteger invertedSectionCount = 0;
  219. __block NSUInteger overridableSectionCount = 0;
  220. __block NSUInteger regularSectionCount = 0;
  221. __block NSUInteger variableCount = 0;
  222. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  223. switch (tag.type) {
  224. case GRMustacheTagTypeInvertedSection:
  225. ++invertedSectionCount;
  226. break;
  227. case GRMustacheTagTypeOverridableSection:
  228. ++overridableSectionCount;
  229. break;
  230. case GRMustacheTagTypeSection:
  231. ++regularSectionCount;
  232. break;
  233. case GRMustacheTagTypeVariable:
  234. ++variableCount;
  235. break;
  236. default:
  237. STAssertTrue(NO, @"");
  238. break;
  239. }
  240. return nil;
  241. }];
  242. {
  243. invertedSectionCount = 0;
  244. overridableSectionCount = 0;
  245. regularSectionCount = 0;
  246. variableCount = 0;
  247. [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:@{ @"object": object } error:NULL];
  248. STAssertEquals(invertedSectionCount, (NSUInteger)0, @"");
  249. STAssertEquals(overridableSectionCount, (NSUInteger)0, @"");
  250. STAssertEquals(regularSectionCount, (NSUInteger)0, @"");
  251. STAssertEquals(variableCount, (NSUInteger)1, @"");
  252. }
  253. {
  254. invertedSectionCount = 0;
  255. overridableSectionCount = 0;
  256. regularSectionCount = 0;
  257. variableCount = 0;
  258. [[GRMustacheTemplate templateFromString:@"{{#object}}...{{/object}}" error:nil] renderObject:@{ @"object": object } error:NULL];
  259. STAssertEquals(invertedSectionCount, (NSUInteger)0, @"");
  260. STAssertEquals(overridableSectionCount, (NSUInteger)0, @"");
  261. STAssertEquals(regularSectionCount, (NSUInteger)1, @"");
  262. STAssertEquals(variableCount, (NSUInteger)0, @"");
  263. }
  264. {
  265. invertedSectionCount = 0;
  266. overridableSectionCount = 0;
  267. regularSectionCount = 0;
  268. variableCount = 0;
  269. [[GRMustacheTemplate templateFromString:@"{{$object}}...{{/object}}" error:nil] renderObject:@{ @"object": object } error:NULL];
  270. STAssertEquals(invertedSectionCount, (NSUInteger)0, @"");
  271. STAssertEquals(overridableSectionCount, (NSUInteger)1, @"");
  272. STAssertEquals(regularSectionCount, (NSUInteger)0, @"");
  273. STAssertEquals(variableCount, (NSUInteger)0, @"");
  274. }
  275. {
  276. invertedSectionCount = 0;
  277. overridableSectionCount = 0;
  278. regularSectionCount = 0;
  279. variableCount = 0;
  280. [[GRMustacheTemplate templateFromString:@"{{^object}}...{{/object}}" error:nil] renderObject:@{ @"object": object } error:NULL];
  281. STAssertEquals(invertedSectionCount, (NSUInteger)1, @"");
  282. STAssertEquals(overridableSectionCount, (NSUInteger)0, @"");
  283. STAssertEquals(regularSectionCount, (NSUInteger)0, @"");
  284. STAssertEquals(variableCount, (NSUInteger)0, @"");
  285. }
  286. }
  287. - (void)testRenderingObjectCanAccessInnerTemplateString
  288. {
  289. {
  290. __block NSString *lastInnerTemplateString = nil;
  291. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  292. lastInnerTemplateString = tag.innerTemplateString;
  293. return nil;
  294. }];
  295. NSDictionary *context = @{ @"object": object };
  296. [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  297. STAssertEqualObjects(lastInnerTemplateString, @"", @"");
  298. }
  299. {
  300. __block NSString *lastInnerTemplateString = nil;
  301. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  302. [lastInnerTemplateString release];
  303. lastInnerTemplateString = [tag.innerTemplateString retain];
  304. return nil;
  305. }];
  306. NSDictionary *context = @{ @"object": object };
  307. [[GRMustacheTemplate templateFromString:@"{{#object}}{{subject}}{{/object}}" error:nil] renderObject:context error:NULL];
  308. STAssertEqualObjects(lastInnerTemplateString, @"{{subject}}", @"");
  309. [lastInnerTemplateString release];
  310. }
  311. }
  312. - (void)testRenderingObjectCanAccessRenderedContent
  313. {
  314. __block NSString *lastRenderedContent = nil;
  315. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  316. [lastRenderedContent release];
  317. lastRenderedContent = [[tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error] retain];
  318. return nil;
  319. }];
  320. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  321. [[GRMustacheTemplate templateFromString:@"{{#object}}{{subject}}==={{subject}}{{/object}}" error:nil] renderObject:context error:NULL];
  322. STAssertEqualObjects(lastRenderedContent, @"---===---", @"");
  323. [lastRenderedContent release];
  324. }
  325. - (void)testRenderingObjectCanRenderCurrentContextInDistinctTemplate
  326. {
  327. {
  328. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  329. GRMustacheTemplate *template = [GRMustacheTemplate templateFromString:@"{{subject}}" error:NULL];
  330. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  331. }];
  332. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  333. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  334. STAssertEqualObjects(result, @"---", @"");
  335. }
  336. {
  337. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  338. GRMustacheTemplate *template = [GRMustacheTemplate templateFromString:@"{{subject}}" error:NULL];
  339. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  340. }];
  341. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  342. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:NULL];
  343. STAssertEqualObjects(result, @"---", @"");
  344. }
  345. }
  346. - (void)testRenderingObjectCanRenderCurrentContextInDistinctTemplateContainingPartial
  347. {
  348. {
  349. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  350. GRMustacheTemplate *template = [tag.templateRepository templateFromString:@"{{> partial}}" error:NULL];
  351. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  352. }];
  353. NSDictionary *partials = @{@"partial": @"{{subject}}"};
  354. GRMustacheTemplateRepository *repository = [GRMustacheTemplateRepository templateRepositoryWithDictionary:partials];
  355. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  356. NSString *result = [[repository templateFromString:@"{{object}}" error:nil] renderObject:context error:NULL];
  357. STAssertEqualObjects(result, @"---", @"");
  358. }
  359. {
  360. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  361. GRMustacheTemplate *template = [tag.templateRepository templateFromString:@"{{> partial}}" error:NULL];
  362. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  363. }];
  364. NSDictionary *partials = @{@"partial": @"{{subject}}"};
  365. GRMustacheTemplateRepository *repository = [GRMustacheTemplateRepository templateRepositoryWithDictionary:partials];
  366. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  367. NSString *result = [[repository templateFromString:@"{{#object}}{{/object}}" error:nil] renderObject:context error:NULL];
  368. STAssertEqualObjects(result, @"---", @"");
  369. }
  370. }
  371. - (void)testRenderingObjectDoesNotAutomaticallyEntersCurrentContext
  372. {
  373. {
  374. GRMustacheAttributedSectionTagHelper *object = [[[GRMustacheAttributedSectionTagHelper alloc] init] autorelease];
  375. object.attribute = @"---";
  376. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:NULL] renderObject:@{ @"object": object } error:NULL];
  377. STAssertEqualObjects(result, @"attribute:", @"");
  378. }
  379. {
  380. GRMustacheAttributedSectionTagHelper *object = [[[GRMustacheAttributedSectionTagHelper alloc] init] autorelease];
  381. object.attribute = @"---";
  382. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:NULL] renderObject:@{ @"object": object } error:NULL];
  383. STAssertEqualObjects(result, @"attribute:", @"");
  384. }
  385. }
  386. - (void)testRenderingObjectCanExplicitelyExtendContextStack
  387. {
  388. {
  389. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  390. context = [context contextByAddingObject:@{ @"subject2": @"+++" }];
  391. GRMustacheTemplate *template = [tag.templateRepository templateFromString:@"{{subject}}{{subject2}}" error:NULL];
  392. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  393. }];
  394. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  395. NSString *result = [[GRMustacheTemplate templateFromString:@"{{object}}" error:NULL] renderObject:context error:NULL];
  396. STAssertEqualObjects(result, @"---+++", @"");
  397. }
  398. {
  399. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  400. context = [context contextByAddingObject:@{ @"subject2": @"+++" }];
  401. return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  402. }];
  403. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  404. NSString *result = [[GRMustacheTemplate templateFromString:@"{{#object}}{{subject}}{{subject2}}{{/object}}" error:NULL] renderObject:context error:NULL];
  405. STAssertEqualObjects(result, @"---+++", @"");
  406. }
  407. }
  408. - (void)testRenderingObjectCanExplicitelyExtendTagDelegateStack
  409. {
  410. {
  411. __block NSUInteger tagWillRenderCount = 0;
  412. GRMustacheTestingDelegate *delegate = [[[GRMustacheTestingDelegate alloc] init] autorelease];
  413. delegate.mustacheTagWillRenderBlock = ^id(GRMustacheTag *tag, id object) {
  414. ++tagWillRenderCount;
  415. return object;
  416. };
  417. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  418. context = [context contextByAddingTagDelegate:delegate];
  419. GRMustacheTemplate *template = [tag.templateRepository templateFromString:@"{{subject}}" error:NULL];
  420. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  421. }];
  422. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  423. NSString *result = [[GRMustacheTemplate templateFromString:@"{{subject}}{{object}}{{subject}}" error:NULL] renderObject:context error:NULL];
  424. STAssertEqualObjects(result, @"---------", @"");
  425. STAssertEquals(tagWillRenderCount, (NSUInteger)1, @"");
  426. }
  427. {
  428. __block NSUInteger tagWillRenderCount = 0;
  429. GRMustacheTestingDelegate *delegate = [[[GRMustacheTestingDelegate alloc] init] autorelease];
  430. delegate.mustacheTagWillRenderBlock = ^id(GRMustacheTag *tag, id object) {
  431. ++tagWillRenderCount;
  432. return object;
  433. };
  434. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  435. context = [context contextByAddingTagDelegate:delegate];
  436. return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  437. }];
  438. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  439. NSString *result = [[GRMustacheTemplate templateFromString:@"{{subject}}{{#object}}{{subject}}{{/object}}{{subject}}" error:NULL] renderObject:context error:NULL];
  440. STAssertEqualObjects(result, @"---------", @"");
  441. STAssertEquals(tagWillRenderCount, (NSUInteger)1, @"");
  442. }
  443. }
  444. - (void)testTagDelegateCallbacksAreCalledWithinSectionRendering
  445. {
  446. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  447. return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  448. }];
  449. GRMustacheTestingDelegate *delegate = [[[GRMustacheTestingDelegate alloc] init] autorelease];
  450. delegate.mustacheTagWillRenderBlock = ^id(GRMustacheTag *tag, id object) {
  451. if (tag.type != GRMustacheTagTypeSection) {
  452. return @"delegate";
  453. } else {
  454. return object;
  455. }
  456. };
  457. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  458. GRMustacheTemplate *template = [GRMustacheTemplate templateFromString:@"{{#object}}{{subject}}{{/object}}" error:NULL];
  459. template.baseContext = [template.baseContext contextByAddingTagDelegate:delegate];
  460. NSString *result = [template renderObject:context error:NULL];
  461. STAssertEqualObjects(result, @"delegate", @"");
  462. }
  463. - (void)testTagDelegateCallbacksAreCalledWithinAlternateTemplateRendering
  464. {
  465. {
  466. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  467. GRMustacheTemplate *template = [GRMustacheTemplate templateFromString:@"{{subject}}" error:NULL];
  468. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  469. }];
  470. GRMustacheTestingDelegate *delegate = [[[GRMustacheTestingDelegate alloc] init] autorelease];
  471. delegate.mustacheTagWillRenderBlock = ^id(GRMustacheTag *tag, id object) {
  472. if (tag.type != GRMustacheTagTypeSection) {
  473. return @"delegate";
  474. } else {
  475. return object;
  476. }
  477. };
  478. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  479. GRMustacheTemplate *template = [GRMustacheTemplate templateFromString:@"{{object}}" error:NULL];
  480. template.baseContext = [template.baseContext contextByAddingTagDelegate:delegate];
  481. NSString *result = [template renderObject:context error:NULL];
  482. STAssertEqualObjects(result, @"delegate", @"");
  483. }
  484. {
  485. id object = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  486. GRMustacheTemplate *template = [GRMustacheTemplate templateFromString:@"{{subject}}" error:NULL];
  487. return [template renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  488. }];
  489. GRMustacheTestingDelegate *delegate = [[[GRMustacheTestingDelegate alloc] init] autorelease];
  490. delegate.mustacheTagWillRenderBlock = ^id(GRMustacheTag *tag, id object) {
  491. if (tag.type != GRMustacheTagTypeSection) {
  492. return @"delegate";
  493. } else {
  494. return object;
  495. }
  496. };
  497. NSDictionary *context = @{ @"object": object, @"subject": @"---" };
  498. GRMustacheTemplate *template = [GRMustacheTemplate templateFromString:@"{{#object}}{{/object}}" error:NULL];
  499. template.baseContext = [template.baseContext contextByAddingTagDelegate:delegate];
  500. NSString *result = [template renderObject:context error:NULL];
  501. STAssertEqualObjects(result, @"delegate", @"");
  502. }
  503. }
  504. - (void)testArrayOfRenderingObjectsInSectionTag
  505. {
  506. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  507. return @"1";
  508. }];
  509. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  510. return @"2";
  511. }];
  512. id items = @{@"items": @[object1, object2] };
  513. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{#items}}{{.}}{{/items}}" error:NULL] renderObject:items error:NULL];
  514. STAssertEqualObjects(rendering, @"12", @"");
  515. }
  516. - (void)testArrayOfRenderingObjectsInSectionTagNeedsExplicitInvocation
  517. {
  518. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  519. NSString *tagRendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  520. return [NSString stringWithFormat:@"[1:%@]", tagRendering];
  521. }];
  522. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  523. NSString *tagRendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
  524. return [NSString stringWithFormat:@"[2:%@]", tagRendering];
  525. }];
  526. id items = @{@"items": @[object1, object2] };
  527. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{#items}}---{{/items}},{{#items}}{{#.}}---{{/.}}{{/items}}" error:NULL] renderObject:items error:NULL];
  528. STAssertEqualObjects(rendering, @"------,[1:---][2:---]", @"");
  529. }
  530. - (void)testArrayOfRenderingObjectsInVariableTag
  531. {
  532. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  533. return @"1";
  534. }];
  535. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  536. return @"2";
  537. }];
  538. id items = @{@"items": @[object1, object2] };
  539. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{items}}" error:NULL] renderObject:items error:NULL];
  540. STAssertEqualObjects(rendering, @"12", @"");
  541. }
  542. - (void)testArrayOfHTMLSafeRenderingObjectsInVariableTag
  543. {
  544. {
  545. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  546. *HTMLSafe = YES;
  547. return @"<1>";
  548. }];
  549. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  550. *HTMLSafe = YES;
  551. return @"<2>";
  552. }];
  553. id items = @{@"items": @[object1, object2] };
  554. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{items}}" error:NULL] renderObject:items error:NULL];
  555. STAssertEqualObjects(rendering, @"<1><2>", @"");
  556. }
  557. {
  558. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  559. *HTMLSafe = YES;
  560. return @"<1>";
  561. }];
  562. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  563. *HTMLSafe = YES;
  564. return @"<2>";
  565. }];
  566. id items = @{@"items": @[object1, object2] };
  567. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{{items}}}" error:NULL] renderObject:items error:NULL];
  568. STAssertEqualObjects(rendering, @"<1><2>", @"");
  569. }
  570. }
  571. - (void)testArrayOfHTMLUnsafeRenderingObjectsInVariableTag
  572. {
  573. {
  574. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  575. *HTMLSafe = NO;
  576. return @"<1>";
  577. }];
  578. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  579. *HTMLSafe = NO;
  580. return @"<2>";
  581. }];
  582. id items = @{@"items": @[object1, object2] };
  583. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{items}}" error:NULL] renderObject:items error:NULL];
  584. STAssertEqualObjects(rendering, @"&lt;1&gt;&lt;2&gt;", @"");
  585. }
  586. {
  587. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  588. *HTMLSafe = NO;
  589. return @"<1>";
  590. }];
  591. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  592. *HTMLSafe = NO;
  593. return @"<2>";
  594. }];
  595. id items = @{@"items": @[object1, object2] };
  596. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{{items}}}" error:NULL] renderObject:items error:NULL];
  597. STAssertEqualObjects(rendering, @"<1><2>", @"");
  598. }
  599. {
  600. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  601. // implicitly not safe
  602. return @"<1>";
  603. }];
  604. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  605. // implicitly not safe
  606. return @"<2>";
  607. }];
  608. id items = @{@"items": @[object1, object2] };
  609. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{items}}" error:NULL] renderObject:items error:NULL];
  610. STAssertEqualObjects(rendering, @"&lt;1&gt;&lt;2&gt;", @"");
  611. }
  612. {
  613. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  614. // implicitly not safe
  615. return @"<1>";
  616. }];
  617. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  618. // implicitly not safe
  619. return @"<2>";
  620. }];
  621. id items = @{@"items": @[object1, object2] };
  622. NSString *rendering = [[GRMustacheTemplate templateFromString:@"{{{items}}}" error:NULL] renderObject:items error:NULL];
  623. STAssertEqualObjects(rendering, @"<1><2>", @"");
  624. }
  625. }
  626. - (void)testArrayOfRenderingObjectsWithInconsistentHTMLEscapingInVariableTag
  627. {
  628. {
  629. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  630. *HTMLSafe = YES;
  631. return @"1";
  632. }];
  633. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  634. *HTMLSafe = NO;
  635. return @"2";
  636. }];
  637. id items = @{@"items": @[object1, object2] };
  638. STAssertThrowsSpecificNamed([[GRMustacheTemplate templateFromString:@"{{items}}" error:NULL] renderObject:items error:NULL], NSException, GRMustacheRenderingException, nil);
  639. }
  640. {
  641. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  642. *HTMLSafe = YES;
  643. return @"1";
  644. }];
  645. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  646. // implicitly not safe
  647. return @"2";
  648. }];
  649. id items = @{@"items": @[object1, object2] };
  650. STAssertThrowsSpecificNamed([[GRMustacheTemplate templateFromString:@"{{items}}" error:NULL] renderObject:items error:NULL], NSException, GRMustacheRenderingException, nil);
  651. }
  652. {
  653. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  654. *HTMLSafe = YES;
  655. return @"1";
  656. }];
  657. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  658. *HTMLSafe = NO;
  659. return @"2";
  660. }];
  661. id items = @{@"items": @[object1, object2] };
  662. STAssertThrowsSpecificNamed([[GRMustacheTemplate templateFromString:@"{{{items}}}" error:NULL] renderObject:items error:NULL], NSException, GRMustacheRenderingException, nil);
  663. }
  664. {
  665. id object1 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  666. *HTMLSafe = YES;
  667. return @"1";
  668. }];
  669. id object2 = [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
  670. // implicitly not safe
  671. return @"2";
  672. }];
  673. id items = @{@"items": @[object1, object2] };
  674. STAssertThrowsSpecificNamed([[GRMustacheTemplate templateFromString:@"{{{items}}}" error:NULL] renderObject:items error:NULL], NSException, GRMustacheRenderingException, nil);
  675. }
  676. }
  677. - (void)testRenderingFacetOfTemplate
  678. {
  679. NSDictionary *partials = @{ @"partial": @"In partial." };
  680. GRMustacheTemplateRepository *repository = [GRMustacheTemplateRepository templateRepositoryWithDictionary:partials];
  681. NSDictionary *context = @{ @"partial": [repository templateNamed:@"partial" error:NULL] };
  682. NSString *result = [[repository templateFromString:@"{{partial}}" error:NULL] renderObject:context error:NULL];
  683. STAssertEqualObjects(result, @"In partial.", @"");
  684. }
  685. - (void)testTemplateAreNotHTMLEscaped
  686. {
  687. NSDictionary *partials = @{ @"partial": @"&<>{{foo}}" };
  688. GRMustacheTemplateRepository *repository = [GRMustacheTemplateRepository templateRepositoryWithDictionary:partials];
  689. NSDictionary *context = @{ @"partial": [repository templateNamed:@"partial" error:NULL] };
  690. NSString *result = [[repository templateFromString:@"{{partial}}{{{partial}}}" error:NULL] renderObject:context error:NULL];
  691. STAssertEqualObjects(result, @"&<>&<>", @"");
  692. }
  693. @end