11package com .hubspot .jinjava .lib .tag ;
22
3+ import static com .hubspot .jinjava .lib .tag .ResourceLocatorTestHelper .getTestResourceLocator ;
34import static com .hubspot .jinjava .loader .RelativePathResolver .CURRENT_PATH_CONTEXT_KEY ;
45import static org .assertj .core .api .Assertions .assertThat ;
5- import static org .junit .Assert .assertTrue ;
66
77import com .google .common .io .Resources ;
88import com .hubspot .jinjava .BaseInterpretingTest ;
1616import java .io .IOException ;
1717import java .nio .charset .Charset ;
1818import java .nio .charset .StandardCharsets ;
19+ import java .util .Map ;
1920import java .util .Optional ;
2021import org .junit .Before ;
2122import org .junit .Test ;
@@ -26,7 +27,8 @@ public class FromTagTest extends BaseInterpretingTest {
2627 public void setup () {
2728 jinjava .setResourceLocator (
2829 new ResourceLocator () {
29- private RelativePathResolver relativePathResolver = new RelativePathResolver ();
30+ private final RelativePathResolver relativePathResolver =
31+ new RelativePathResolver ();
3032
3133 @ Override
3234 public String getString (
@@ -66,25 +68,27 @@ public void itImportsAliasedMacroName() {
6668 }
6769
6870 @ Test
69- public void importedCycleDected () {
71+ public void importedCycleDetected () {
7072 fixture ("from-recursion" );
71- assertTrue (
73+ assertThat (
7274 interpreter
7375 .getErrorsCopy ()
7476 .stream ()
7577 .anyMatch (e -> e .getCategory () == BasicTemplateErrorCategory .FROM_CYCLE_DETECTED )
76- );
78+ )
79+ .isTrue ();
7780 }
7881
7982 @ Test
80- public void importedIndirectCycleDected () {
83+ public void importedIndirectCycleDetected () {
8184 fixture ("from-a-to-b" );
82- assertTrue (
85+ assertThat (
8386 interpreter
8487 .getErrorsCopy ()
8588 .stream ()
8689 .anyMatch (e -> e .getCategory () == BasicTemplateErrorCategory .FROM_CYCLE_DETECTED )
87- );
90+ )
91+ .isTrue ();
8892 }
8993
9094 @ Test
@@ -112,6 +116,190 @@ public void itDefersImport() {
112116 assertThat (spacer .isDeferred ()).isTrue ();
113117 }
114118
119+ @ Test
120+ public void itResolvesNestedRelativeImports () throws Exception {
121+ jinjava .setResourceLocator (
122+ getTestResourceLocator (
123+ Map .of (
124+ "level0.jinja" ,
125+ "{% from 'level1/nested.jinja' import macro1 %}{{ macro1() }}" ,
126+ "level1/nested.jinja" ,
127+ "{% from '../level1/deeper/macro.jinja' import macro2 %}{% macro macro1() %}L1:{{ macro2() }}{% endmacro %}" ,
128+ "level1/deeper/macro.jinja" ,
129+ "{% from '../../utils/helper.jinja' import helper %}{% macro macro2() %}L2:{{ helper() }}{% endmacro %}" ,
130+ "utils/helper.jinja" ,
131+ "{% macro helper() %}HELPER{% endmacro %}"
132+ )
133+ )
134+ );
135+
136+ interpreter .getContext ().getCurrentPathStack ().push ("level0.jinja" , 1 , 0 );
137+ String result = interpreter .render (interpreter .getResource ("level0.jinja" ));
138+
139+ assertThat (interpreter .getErrors ()).isEmpty ();
140+ assertThat (result .trim ()).isEqualTo ("L1:L2:HELPER" );
141+ }
142+
143+ @ Test
144+ public void itMaintainsPathStackIntegrity () throws Exception {
145+ jinjava .setResourceLocator (
146+ getTestResourceLocator (
147+ Map .of (
148+ "root.jinja" ,
149+ "{% from 'simple/macro.jinja' import simple_macro %}{{ simple_macro() }}" ,
150+ "simple/macro.jinja" ,
151+ "{% macro simple_macro() %}SIMPLE{% endmacro %}"
152+ )
153+ )
154+ );
155+
156+ interpreter .getContext ().getCurrentPathStack ().push ("root.jinja" , 1 , 0 );
157+ Optional <String > initialTopPath = interpreter
158+ .getContext ()
159+ .getCurrentPathStack ()
160+ .peek ();
161+
162+ interpreter .render (interpreter .getResource ("root.jinja" ));
163+
164+ assertThat (interpreter .getContext ().getCurrentPathStack ().peek ())
165+ .isEqualTo (initialTopPath );
166+ assertThat (interpreter .getErrors ()).isEmpty ();
167+ }
168+
169+ @ Test
170+ public void itWorksWithIncludeAndFromTogether () throws Exception {
171+ jinjava .setResourceLocator (
172+ getTestResourceLocator (
173+ Map .of (
174+ "mixed-tags.jinja" ,
175+ "{% from 'macros/test.jinja' import test_macro %}{% include 'includes/content.jinja' %}{{ test_macro() }}" ,
176+ "macros/test.jinja" ,
177+ "{% from '../utils/shared.jinja' import shared %}{% macro test_macro() %}MACRO:{{ shared() }}{% endmacro %}" ,
178+ "includes/content.jinja" ,
179+ "{% from '../utils/shared.jinja' import shared %}INCLUDE:{{ shared() }}" ,
180+ "utils/shared.jinja" ,
181+ "{% macro shared() %}SHARED{% endmacro %}"
182+ )
183+ )
184+ );
185+
186+ interpreter .getContext ().getCurrentPathStack ().push ("mixed-tags.jinja" , 1 , 0 );
187+ String result = interpreter .render (interpreter .getResource ("mixed-tags.jinja" ));
188+
189+ assertThat (interpreter .getErrors ()).isEmpty ();
190+ assertThat (result .trim ()).contains ("INCLUDE:SHARED" );
191+ assertThat (result .trim ()).contains ("MACRO:SHARED" );
192+ }
193+
194+ @ Test
195+ public void itResolvesUpAndAcrossDirectoryPaths () throws Exception {
196+ jinjava .setResourceLocator (
197+ getTestResourceLocator (
198+ Map .of (
199+ "theme/hubl-modules/navigation.module/module.hubl.html" ,
200+ "{% from '../../partials/atoms/link/link.hubl.html' import link_macro %}{{ link_macro() }}" ,
201+ "theme/partials/atoms/link/link.hubl.html" ,
202+ "{% from '../icons/icons.hubl.html' import icon_macro %}{% macro link_macro() %}LINK:{{ icon_macro() }}{% endmacro %}" ,
203+ "theme/partials/atoms/icons/icons.hubl.html" ,
204+ "{% macro icon_macro() %}ICON{% endmacro %}"
205+ )
206+ )
207+ );
208+
209+ interpreter
210+ .getContext ()
211+ .getCurrentPathStack ()
212+ .push ("theme/hubl-modules/navigation.module/module.hubl.html" , 1 , 0 );
213+ String result = interpreter .render (
214+ interpreter .getResource ("theme/hubl-modules/navigation.module/module.hubl.html" )
215+ );
216+
217+ assertThat (interpreter .getErrors ()).isEmpty ();
218+ assertThat (result .trim ()).isEqualTo ("LINK:ICON" );
219+ }
220+
221+ @ Test
222+ public void itResolvesProjectsAbsolutePathsWithNestedRelativeImports ()
223+ throws Exception {
224+ jinjava .setResourceLocator (
225+ getTestResourceLocator (
226+ Map .of (
227+ "@projects/theme-a/modules/header/header.html" ,
228+ "{% from '../../components/button.html' import render_button %}{{ render_button('primary') }}" ,
229+ "@projects/theme-a/components/button.html" ,
230+ "{% from '../utils/icons.html' import get_icon %}{% macro render_button(type) %}{{ type }}-{{ get_icon() }}{% endmacro %}" ,
231+ "@projects/theme-a/utils/icons.html" ,
232+ "{% macro get_icon() %}ICON{% endmacro %}"
233+ )
234+ )
235+ );
236+
237+ interpreter
238+ .getContext ()
239+ .getCurrentPathStack ()
240+ .push ("@projects/theme-a/modules/header/header.html" , 1 , 0 );
241+ String result = interpreter .render (
242+ interpreter .getResource ("@projects/theme-a/modules/header/header.html" )
243+ );
244+
245+ assertThat (interpreter .getErrors ()).isEmpty ();
246+ assertThat (result .trim ()).isEqualTo ("primary-ICON" );
247+ }
248+
249+ @ Test
250+ public void itResolvesHubspotAbsolutePathsWithNestedRelativeImports () throws Exception {
251+ jinjava .setResourceLocator (
252+ getTestResourceLocator (
253+ Map .of (
254+ "@hubspot/modules/forms/contact-form.html" ,
255+ "{% from '../../shared/validation.html' import validate_field %}{{ validate_field('email') }}" ,
256+ "@hubspot/shared/validation.html" ,
257+ "{% from '../helpers/formatters.html' import format_error %}{% macro validate_field(field) %}{{ format_error(field) }}{% endmacro %}" ,
258+ "@hubspot/helpers/formatters.html" ,
259+ "{% macro format_error(field) %}ERROR:{{ field }}{% endmacro %}"
260+ )
261+ )
262+ );
263+
264+ interpreter
265+ .getContext ()
266+ .getCurrentPathStack ()
267+ .push ("@hubspot/modules/forms/contact-form.html" , 1 , 0 );
268+ String result = interpreter .render (
269+ interpreter .getResource ("@hubspot/modules/forms/contact-form.html" )
270+ );
271+
272+ assertThat (interpreter .getErrors ()).isEmpty ();
273+ assertThat (result .trim ()).isEqualTo ("ERROR:email" );
274+ }
275+
276+ @ Test
277+ public void itResolvesMixedAbsoluteAndRelativeImports () throws Exception {
278+ jinjava .setResourceLocator (
279+ getTestResourceLocator (
280+ Map .of (
281+ "@projects/mixed/module.html" ,
282+ "{% from '@hubspot/shared/globals.html' import global_helper %}{{ global_helper() }}" ,
283+ "@hubspot/shared/globals.html" ,
284+ "{% from '../utils/common.html' import format_text %}{% macro global_helper() %}{{ format_text('MIXED') }}{% endmacro %}" ,
285+ "@hubspot/utils/common.html" ,
286+ "{% macro format_text(text) %}FORMAT:{{ text }}{% endmacro %}"
287+ )
288+ )
289+ );
290+
291+ interpreter
292+ .getContext ()
293+ .getCurrentPathStack ()
294+ .push ("@projects/mixed/module.html" , 1 , 0 );
295+ String result = interpreter .render (
296+ interpreter .getResource ("@projects/mixed/module.html" )
297+ );
298+
299+ assertThat (interpreter .getErrors ()).isEmpty ();
300+ assertThat (result .trim ()).isEqualTo ("FORMAT:MIXED" );
301+ }
302+
115303 private String fixture (String name ) {
116304 return interpreter .renderFlat (fixtureText (name ));
117305 }
0 commit comments