/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.mail.internal.factory.template; import java.io.Writer; import java.net.URL; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; import javax.inject.Provider; import javax.mail.MessagingException; import org.apache.velocity.VelocityContext; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.xwiki.bridge.DocumentAccessBridge; import org.xwiki.model.reference.DocumentReference; import org.xwiki.test.mockito.MockitoComponentMockingRule; import org.xwiki.velocity.VelocityEngine; import org.xwiki.velocity.VelocityManager; import org.xwiki.velocity.XWikiVelocityException; import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.objects.BaseObject; import com.xpn.xwiki.web.XWikiRequest; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * Unit tests for {@link org.xwiki.mail.internal.factory.template.DefaultMailTemplateManager}. * * @version $Id: d967e87fafdfecbe04aea779f84706382fc3cc21 $ * @since 6.1RC1 */ public class DefaultMailTemplateManagerTest { @Rule public MockitoComponentMockingRule<DefaultMailTemplateManager> mocker = new MockitoComponentMockingRule<>(DefaultMailTemplateManager.class); private XWiki xwiki; @Before public void setUp() throws Exception { XWikiContext xwikiContext = mock(XWikiContext.class); Provider<XWikiContext> contextProvider = this.mocker.registerMockComponent(XWikiContext.TYPE_PROVIDER); when(contextProvider.get()).thenReturn(xwikiContext); this.xwiki = mock(XWiki.class); when(xwikiContext.getWiki()).thenReturn(this.xwiki); when(this.xwiki.getDefaultLocale(xwikiContext)).thenReturn(Locale.ENGLISH); XWikiDocument document = mock(XWikiDocument.class); when(this.xwiki.getDocument(any(DocumentReference.class), eq(xwikiContext))).thenReturn(document); BaseObject object = mock(BaseObject.class); when(document.getXObjects(any())).thenReturn(Collections.singletonList(object)); // Needed so that xcontext.setURLFactory(new ExternalServletURLFactory(xcontext)); will not fail even // though we don't want this line to have any behavior. when(xwikiContext.getURL()).thenReturn(new URL("http:/localhost:8080/dummy")); when(xwikiContext.getRequest()).thenReturn(mock(XWikiRequest.class)); } @Test public void evaluate() throws Exception { DocumentAccessBridge documentBridge = this.mocker.getInstance(DocumentAccessBridge.class); DocumentReference documentReference = new DocumentReference("wiki", "space", "page"); when(documentBridge.getProperty(same(documentReference), any(), anyInt(), eq("html"))) .thenReturn("Hello <b>${name}</b> <br />${email}"); VelocityEngine velocityEngine = mock(VelocityEngine.class); VelocityManager velocityManager = this.mocker.getInstance(VelocityManager.class); when(velocityManager.getVelocityEngine()).thenReturn(velocityEngine); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); ((Writer) args[1]).write("Hello <b>John Doe</b> <br />john@doe.com"); return null; } }).when(velocityEngine).evaluate(any(VelocityContext.class), any(Writer.class), any(), eq("Hello <b>${name}</b> <br />${email}")); String result = this.mocker.getComponentUnderTest().evaluate(documentReference, "html", Collections.emptyMap()); assertEquals(result, "Hello <b>John Doe</b> <br />john@doe.com"); } @Test public void evaluateWithLanguage() throws Exception { DocumentAccessBridge documentBridge = this.mocker.getInstance(DocumentAccessBridge.class); DocumentReference documentReference = new DocumentReference("wiki", "space", "page"); when(documentBridge.getObjectNumber(any(), any(), eq("language"), eq("fr"))).thenReturn(1); when(documentBridge.getProperty(any(DocumentReference.class), any(), eq(1), eq("html"))) .thenReturn("Salut <b>${name}</b> <br />${email}"); VelocityEngine velocityEngine = mock(VelocityEngine.class); VelocityManager velocityManager = this.mocker.getInstance(VelocityManager.class); when(velocityManager.getVelocityEngine()).thenReturn(velocityEngine); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); ((Writer) args[1]).write("Salut <b>John Doe</b> <br />john@doe.com"); return null; } }).when(velocityEngine).evaluate(any(VelocityContext.class), any(Writer.class), any(), eq("Salut <b>${name}</b> <br />${email}")); String result = this.mocker.getComponentUnderTest().evaluate(documentReference, "html", Collections.emptyMap(), Locale.FRENCH); verify(documentBridge).getObjectNumber(any(), any(), eq("language"), eq("fr")); assertEquals(result, "Salut <b>John Doe</b> <br />john@doe.com"); } @Test public void evaluateWithObjectNotFoundWithLanguagePassed() throws Exception { DocumentAccessBridge documentBridge = this.mocker.getInstance(DocumentAccessBridge.class); DocumentReference documentReference = new DocumentReference("wiki", "space", "page"); // First call with the passed language, return -1 (No XWiki.Mail xobject found) when(documentBridge.getObjectNumber(any(), any(), eq("language"), eq("fr"))).thenReturn(-1); // Second call with the default language (en), return one (Only XWiki.Mail xobject is found) when(documentBridge.getObjectNumber(any(), any(), eq("language"), eq("en"))).thenReturn(1); when(documentBridge.getProperty(any(DocumentReference.class), any(), eq(1), eq("html"))) .thenReturn("Salut <b>${name}</b> <br />${email}"); VelocityEngine velocityEngine = mock(VelocityEngine.class); VelocityManager velocityManager = this.mocker.getInstance(VelocityManager.class); when(velocityManager.getVelocityEngine()).thenReturn(velocityEngine); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); ((Writer) args[1]).write("Salut <b>John Doe</b> <br />john@doe.com"); return null; } }).when(velocityEngine).evaluate(any(), any(), any(), eq("Salut <b>${name}</b> <br />${email}")); String result = this.mocker.getComponentUnderTest().evaluate(documentReference, "html", Collections.emptyMap(), Locale.FRENCH); verify(documentBridge).getObjectNumber(any(), any(), eq("language"), eq("fr")); verify(documentBridge).getObjectNumber(any(), any(), eq("language"), eq("en")); assertEquals(result, "Salut <b>John Doe</b> <br />john@doe.com"); } @Test public void evaluateWithObjectNotFoundWithDefaultLanguage() throws Exception { DocumentAccessBridge documentBridge = this.mocker.getInstance(DocumentAccessBridge.class); DocumentReference documentReference = new DocumentReference("wiki", "space", "page"); // First call with the passed language, return -1 (No XWiki.Mail xobject found) when(documentBridge.getObjectNumber(any(), any(), eq("language"), eq("fr"))).thenReturn(-1); // Second call with the default language, return -1 (No XWiki.Mail xobject found) when(documentBridge.getObjectNumber(any(), any(), eq("language"), eq("en"))).thenReturn(-1); when(documentBridge.getProperty(any(DocumentReference.class), any(), eq(0), eq("html"))) .thenReturn("Salut <b>${name}</b> <br />${email}"); VelocityEngine velocityEngine = mock(VelocityEngine.class); VelocityManager velocityManager = this.mocker.getInstance(VelocityManager.class); when(velocityManager.getVelocityEngine()).thenReturn(velocityEngine); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); ((Writer) args[1]).write("Salut <b>John Doe</b> <br />john@doe.com"); return null; } }).when(velocityEngine).evaluate(any(), any(), any(), eq("Salut <b>${name}</b> <br />${email}")); String result = this.mocker.getComponentUnderTest().evaluate(documentReference, "html", Collections.emptyMap(), Locale.FRENCH); verify(documentBridge).getObjectNumber(any(), any(), eq("language"), eq("fr")); verify(documentBridge).getObjectNumber(any(), any(), eq("language"), eq("en")); assertEquals(result, "Salut <b>John Doe</b> <br />john@doe.com"); } @Test public void evaluateWithErrorNoObjectMatches() throws Exception { XWikiDocument document = mock(XWikiDocument.class); when(this.xwiki.getDocument(any(DocumentReference.class), any())).thenReturn(document); BaseObject object1 = mock(BaseObject.class); BaseObject object2 = mock(BaseObject.class); List<BaseObject> xobjects = Arrays.asList(object1, object2); when(document.getXObjects(any())).thenReturn(xobjects); DocumentAccessBridge documentBridge = this.mocker.getInstance(DocumentAccessBridge.class); DocumentReference documentReference = new DocumentReference("wiki", "space", "page"); // First call with the passed language, return -1 (No XWiki.Mail xobject found) when(documentBridge.getObjectNumber(any(), any(), eq("language"), eq("fr"))).thenReturn(-1); // Second call with the default language, return -1 (No XWiki.Mail xobject found) when(documentBridge.getObjectNumber(any(), any(), eq("language"), eq("en"))).thenReturn(-1); try { this.mocker.getComponentUnderTest().evaluate(documentReference, "html", Collections.emptyMap(), Locale.FRENCH); fail("Should have thrown an exception here!"); } catch (MessagingException expected) { assertEquals( "No [Document XWiki.Mail] object matches the locale [fr] or the default locale [en] " +"in the Document [wiki:space.page]", expected.getMessage()); } } @Test public void evaluateWhenVelocityError() throws Exception { DocumentAccessBridge documentBridge = this.mocker.getInstance(DocumentAccessBridge.class); DocumentReference documentReference = new DocumentReference("wiki", "space", "page"); when(documentBridge.getProperty(same(documentReference), any(), anyInt(), eq("html"))) .thenReturn("Hello <b>${name}</b> <br />${email}"); VelocityEngine velocityEngine = mock(VelocityEngine.class); VelocityManager velocityManager = this.mocker.getInstance(VelocityManager.class); when(velocityManager.getVelocityEngine()).thenReturn(velocityEngine); when(velocityEngine.evaluate(any(VelocityContext.class), any(Writer.class), any(), eq("Hello <b>${name}</b> <br />${email}"))).thenThrow(new XWikiVelocityException("Error")); try { this.mocker.getComponentUnderTest().evaluate(documentReference, "html", Collections.<String, Object>emptyMap()); fail("Should have thrown an exception here!"); } catch (MessagingException expected) { assertEquals("Failed to evaluate property [html] for Document [wiki:space.page] and locale [null]", expected.getMessage()); } } }