com.xpn.xwiki.XWikiTest.java Source code

Java tutorial

Introduction

Here is the source code for com.xpn.xwiki.XWikiTest.java

Source

/*
 * 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 com.xpn.xwiki;

import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.Cookie;

import org.apache.commons.collections.IteratorUtils;
import org.jmock.Mock;
import org.jmock.core.Invocation;
import org.jmock.core.stub.CustomStub;
import org.xwiki.bridge.event.DocumentCreatedEvent;
import org.xwiki.bridge.event.DocumentCreatingEvent;
import org.xwiki.bridge.event.DocumentDeletedEvent;
import org.xwiki.bridge.event.DocumentDeletingEvent;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.observation.EventListener;
import org.xwiki.observation.ObservationManager;
import org.xwiki.rendering.syntax.Syntax;

import com.xpn.xwiki.doc.XWikiAttachment;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.BaseProperty;
import com.xpn.xwiki.objects.StringProperty;
import com.xpn.xwiki.objects.classes.PropertyClass;
import com.xpn.xwiki.store.XWikiHibernateStore;
import com.xpn.xwiki.store.XWikiHibernateVersioningStore;
import com.xpn.xwiki.store.XWikiStoreInterface;
import com.xpn.xwiki.store.XWikiVersioningStoreInterface;
import com.xpn.xwiki.test.AbstractBridgedXWikiComponentTestCase;
import com.xpn.xwiki.web.XWikiRequest;
import com.xpn.xwiki.web.XWikiServletRequest;
import com.xpn.xwiki.web.XWikiServletRequestStub;

/**
 * Unit tests for {@link com.xpn.xwiki.XWiki}.
 * 
 * @version $Id: 3082de28ee9ae76153d896a71730a43743be45dd $
 */
public class XWikiTest extends AbstractBridgedXWikiComponentTestCase {
    private XWikiDocument document;

    private XWiki xwiki;

    private Mock mockXWikiStore;

    private Mock mockXWikiVersioningStore;

    private Map<String, XWikiDocument> docs = new HashMap<String, XWikiDocument>();

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        this.document = new XWikiDocument(new DocumentReference("Wiki", "MilkyWay", "Fidis"));
        getContext().setRequest(new XWikiServletRequestStub());
        getContext().setURL(new URL("http://localhost:8080/xwiki/bin/view/MilkyWay/Fidis"));

        this.xwiki = new XWiki(new XWikiConfig(), getContext()) {
            protected void registerWikiMacros() {
            }

            // Avoid all the error at XWiki initialization
            @Override
            public String getXWikiPreference(String prefname, String defaultValue, XWikiContext context) {
                if (prefname.equals("plugins") || prefname.startsWith("macros_")) {
                    return defaultValue;
                } else {
                    return super.getXWikiPreference(prefname, defaultValue, context);
                }
            }
        };
        getContext().setWiki(this.xwiki);

        // Ensure that no Velocity Templates are going to be used when executing Velocity since otherwise
        // the Velocity init would fail (since by default the macros.vm templates wouldn't be found as we're
        // not providing it in our unit test resources).
        this.xwiki.getConfig().setProperty("xwiki.render.velocity.macrolist", "");

        this.mockXWikiStore = mock(XWikiHibernateStore.class, new Class[] { XWiki.class, XWikiContext.class },
                new Object[] { this.xwiki, getContext() });
        this.mockXWikiStore.stubs().method("loadXWikiDoc")
                .will(new CustomStub("Implements XWikiStoreInterface.loadXWikiDoc") {
                    public Object invoke(Invocation invocation) throws Throwable {
                        XWikiDocument shallowDoc = (XWikiDocument) invocation.parameterValues.get(0);
                        if (XWikiTest.this.docs.containsKey(shallowDoc.getName())) {
                            return XWikiTest.this.docs.get(shallowDoc.getName());
                        } else {
                            return shallowDoc;
                        }
                    }
                });
        this.mockXWikiStore.stubs().method("saveXWikiDoc")
                .will(new CustomStub("Implements XWikiStoreInterface.saveXWikiDoc") {
                    public Object invoke(Invocation invocation) throws Throwable {
                        XWikiDocument document = (XWikiDocument) invocation.parameterValues.get(0);
                        document.setNew(false);
                        document.setStore((XWikiStoreInterface) XWikiTest.this.mockXWikiStore.proxy());
                        XWikiTest.this.docs.put(document.getName(), document);
                        return null;
                    }
                });
        this.mockXWikiStore.stubs().method("deleteXWikiDoc")
                .will(new CustomStub("Implements XWikiStoreInterface.deleteXWikiDoc") {
                    public Object invoke(Invocation invocation) throws Throwable {
                        XWikiDocument document = (XWikiDocument) invocation.parameterValues.get(0);
                        XWikiTest.this.docs.remove(document.getName());
                        return null;
                    }
                });
        this.mockXWikiStore.stubs().method("getTranslationList").will(returnValue(Collections.EMPTY_LIST));
        this.mockXWikiStore.stubs().method("exists").will(returnValue(true));

        this.mockXWikiVersioningStore = mock(XWikiHibernateVersioningStore.class,
                new Class[] { XWiki.class, XWikiContext.class }, new Object[] { this.xwiki, getContext() });
        this.mockXWikiVersioningStore.stubs().method("getXWikiDocumentArchive").will(returnValue(null));
        this.mockXWikiVersioningStore.stubs().method("resetRCSArchive").will(returnValue(null));

        this.xwiki.setStore((XWikiStoreInterface) this.mockXWikiStore.proxy());
        this.xwiki.setVersioningStore((XWikiVersioningStoreInterface) this.mockXWikiVersioningStore.proxy());
        this.xwiki.saveDocument(this.document, getContext());

        this.document.setCreator("Condor");
        this.document.setAuthor("Albatross");

        this.xwiki.saveDocument(this.document, getContext());
    }

    public void testAuthorAfterDocumentCopy() throws XWikiException {
        DocumentReference copyReference = new DocumentReference("Lyre",
                this.document.getDocumentReference().getLastSpaceReference());
        DocumentReference author = this.document.getAuthorReference();
        this.xwiki.copyDocument(this.document.getDocumentReference(), copyReference, getContext());
        XWikiDocument copy = this.xwiki.getDocument(copyReference, getContext());

        assertEquals(author, copy.getAuthorReference());
    }

    public void testCreatorAfterDocumentCopy() throws XWikiException {
        DocumentReference copyReference = new DocumentReference("Sirius",
                this.document.getDocumentReference().getLastSpaceReference());
        DocumentReference creator = this.document.getCreatorReference();
        this.xwiki.copyDocument(this.document.getDocumentReference(), copyReference, getContext());
        XWikiDocument copy = this.xwiki.getDocument(copyReference, getContext());

        assertEquals(creator, copy.getCreatorReference());
    }

    public void testCreationDateAfterDocumentCopy() throws XWikiException, InterruptedException {
        Date sourceCreationDate = this.document.getCreationDate();
        Thread.sleep(1000);
        DocumentReference copyReference = new DocumentReference(
                this.document.getDocumentReference().getName() + "Copy",
                this.document.getDocumentReference().getLastSpaceReference());
        this.xwiki.copyDocument(this.document.getDocumentReference(), copyReference, getContext());
        XWikiDocument copy = this.xwiki.getDocument(copyReference, getContext());

        assertTrue(copy.getCreationDate().equals(sourceCreationDate));
    }

    public void testParseTemplateConsidersObjectField() throws XWikiException {
        DocumentReference skinReference = new DocumentReference("xwiki", "XWiki", "XWikiSkins");
        XWikiDocument skinClass = new XWikiDocument(skinReference);
        skinClass.getXClass().addTextAreaField("template.vm", "template", 80, 20);
        this.xwiki.saveDocument(skinClass, getContext());

        DocumentReference mySkinReference = new DocumentReference("xwiki", "XWiki", "Skin");
        XWikiDocument skinDocument = new XWikiDocument(mySkinReference);
        BaseObject obj = skinDocument.newXObject(skinReference, getContext());
        obj.setLargeStringValue("template.vm", "parsing a field");
        this.xwiki.saveDocument(skinDocument, getContext());

        getContext().put("skin", "XWiki.Skin");
        assertEquals("XWiki.Skin", this.xwiki.getSkin(getContext()));
        assertFalse(this.xwiki.getDocument(mySkinReference, getContext()).isNew());
        assertEquals(skinDocument, this.xwiki.getDocument(mySkinReference, getContext()));
        assertEquals("parsing a field", this.xwiki.parseTemplate("template.vm", getContext()));
    }

    /**
     * See XWIKI-2096
     */
    public void testParseTemplateConsidersAttachment() throws XWikiException {
        XWikiDocument skin = new XWikiDocument(new DocumentReference("Wiki", "XWiki", "Skin"));
        XWikiAttachment attachment = new XWikiAttachment();
        skin.getAttachmentList().add(attachment);
        attachment.setContent("parsing an attachment".getBytes());
        attachment.setFilename("template.vm");
        attachment.setDoc(skin);
        this.xwiki.saveDocument(skin, getContext());
        getContext().put("skin", "XWiki.Skin");
        assertEquals("XWiki.Skin", this.xwiki.getSkin(getContext()));
        assertFalse(this.xwiki.getDocument("XWiki.Skin", getContext()).isNew());
        assertEquals(skin, this.xwiki.getDocument("XWiki.Skin", getContext()));
        assertEquals("parsing an attachment", this.xwiki.parseTemplate("template.vm", getContext()));
    }

    /**
     * See XWIKI-2098
     */
    public void testParseTemplateConsidersObjectFieldBeforeAttachment() throws Exception {
        DocumentReference skinReference = new DocumentReference("xwiki", "XWiki", "XWikiSkins");
        XWikiDocument skinClass = new XWikiDocument(skinReference);
        skinClass.getXClass().addTextAreaField("template.vm", "template", 80, 20);
        this.xwiki.saveDocument(skinClass, getContext());

        DocumentReference mySkinReference = new DocumentReference("xwiki", "XWiki", "Skin");
        XWikiDocument skinDocument = new XWikiDocument(mySkinReference);
        BaseObject obj = skinDocument.newXObject(skinReference, getContext());
        obj.setLargeStringValue("template.vm", "parsing a field");
        XWikiAttachment attachment = new XWikiAttachment();
        skinDocument.getAttachmentList().add(attachment);
        attachment.setContent(new ByteArrayInputStream("parsing an attachment".getBytes()));
        attachment.setFilename("template.vm");
        attachment.setDoc(skinDocument);
        this.xwiki.saveDocument(skinDocument, getContext());
        getContext().put("skin", "XWiki.Skin");
        assertEquals("XWiki.Skin", this.xwiki.getSkin(getContext()));
        assertFalse(this.xwiki.getDocument(mySkinReference, getContext()).isNew());
        assertEquals(skinDocument, this.xwiki.getDocument(mySkinReference, getContext()));
        assertEquals("parsing a field", this.xwiki.parseTemplate("template.vm", getContext()));
    }

    public void testClearNameWithoutStripDotsWithoutAscii() {
        assertEquals("ee{&.txt", this.xwiki.clearName("\u00E9\u00EA{&.txt", false, false, getContext()));
    }

    public void testClearNameWithoutStripDotsWithAscii() {
        assertEquals("ee.txt", this.xwiki.clearName("\u00E9\u00EA{&.txt", false, true, getContext()));
    }

    public void testClearNameWithStripDotsWithoutAscii() {
        assertEquals("ee{&txt", this.xwiki.clearName("\u00E9\u00EA{&.txt", true, false, getContext()));
    }

    public void testClearNameWithStripDotsWithAscii() {
        assertEquals("eetxt", this.xwiki.clearName("\u00E9\u00EA{&.txt", true, true, getContext()));
    }

    public void testGetDocumentNameFromPath() {
        assertEquals("Main.WebHome", this.xwiki.getDocumentNameFromPath("", getContext()));
        assertEquals("Main.WebHome", this.xwiki.getDocumentNameFromPath("/", getContext()));
        assertEquals("Main.Document", this.xwiki.getDocumentNameFromPath("/Document", getContext()));
        assertEquals("Space.WebHome", this.xwiki.getDocumentNameFromPath("/Space/", getContext()));
        assertEquals("Space.Document", this.xwiki.getDocumentNameFromPath("/Space/Document", getContext()));
        assertEquals("Space.WebHome", this.xwiki.getDocumentNameFromPath("/view/Space/", getContext()));
        assertEquals("Space.Document", this.xwiki.getDocumentNameFromPath("/view/Space/Document", getContext()));
        assertEquals("Space.Document", this.xwiki.getDocumentNameFromPath("/view/Space/Document/", getContext()));
        assertEquals("Space.Document",
                this.xwiki.getDocumentNameFromPath("/view/Space/Document/some/ignored/paths", getContext()));

        // Test URL encoding and verify an encoded forward slash ("/" - encoded as %2F) works too.
        assertEquals("My Space.My/Document",
                this.xwiki.getDocumentNameFromPath("/My%20Space/My%2FDocument", getContext()));
    }

    /**
     * We only verify here that the saveDocument API calls the Observation component.
     */
    public void testSaveDocumentSendsObservationEvents() throws Exception {
        Mock mockListener = mock(EventListener.class);
        mockListener.stubs().method("getName").will(returnValue("testlistener"));
        DocumentReference ref = new DocumentReference("xwikitest", "Some", "Document");
        mockListener.expects(once()).method("getEvents")
                .will(returnValue(Arrays.asList(new DocumentCreatedEvent(ref), new DocumentCreatingEvent(ref))));

        ObservationManager om = getComponentManager().lookup(ObservationManager.class);
        om.addListener((EventListener) mockListener.proxy());

        XWikiDocument document = new XWikiDocument(new DocumentReference("xwikitest", "Some", "Document"));
        document.setContent("the content");

        // Ensure that the onEvent method has been called before and after the save
        mockListener.expects(once()).method("onEvent").with(isA(DocumentCreatingEvent.class), same(document),
                isA(XWikiContext.class));
        mockListener.expects(once()).method("onEvent").with(isA(DocumentCreatedEvent.class), same(document),
                isA(XWikiContext.class));

        this.xwiki.saveDocument(document, getContext());
    }

    /**
     * We only verify here that the deleteDocument API calls the Observation component.
     */
    public void testDeleteDocumentSendsObservationEvents() throws Exception {
        Mock mockListener = mock(EventListener.class);
        mockListener.stubs().method("getName").will(returnValue("testlistener"));
        DocumentReference ref = new DocumentReference("xwikitest", "Another", "Document");
        mockListener.expects(once()).method("getEvents")
                .will(returnValue(Arrays.asList(new DocumentDeletedEvent(ref), new DocumentDeletingEvent(ref))));

        ObservationManager om = getComponentManager().lookup(ObservationManager.class);
        om.addListener((EventListener) mockListener.proxy());

        XWikiDocument document = new XWikiDocument(new DocumentReference("xwikitest", "Another", "Document"));
        document.setContent("the content");

        // Not expectation on mock Listener since we're not subscribed to Document save events

        this.xwiki.saveDocument(document, getContext());

        // Ensure that the onEvent method has been called before and after the deletion
        mockListener.expects(once()).method("onEvent").with(isA(DocumentDeletingEvent.class),
                isA(XWikiDocument.class), isA(XWikiContext.class));
        mockListener.expects(once()).method("onEvent").with(isA(DocumentDeletedEvent.class),
                isA(XWikiDocument.class), isA(XWikiContext.class));

        this.xwiki.deleteDocument(document, false, getContext());
    }

    public void testLanguageSelection() {
        getContext().setRequest(new XWikiServletRequest(null) {
            @SuppressWarnings("unchecked")
            @Override
            public Enumeration getLocales() {
                ArrayList<Locale> locales = new ArrayList<Locale>();
                locales.add(new Locale("*"));
                locales.add(new Locale("en_US"));
                locales.add(new Locale("fr"));
                locales.add(new Locale("de"));
                return IteratorUtils.asEnumeration(locales.iterator());
            }

            @Override
            public String getHeader(String s) {
                if ("language".equals(s)) {
                    return null;
                }
                return "en";
            }

            @Override
            public Cookie getCookie(String cookieName) {
                return null;
            }
        });
        assertEquals("fr", this.xwiki.getLanguagePreference(getContext()));
    }

    public void testGetCurrentContentSyntaxId() {
        XWikiDocument doc1 = new XWikiDocument();
        doc1.setSyntax(Syntax.CREOLE_1_0);
        XWikiDocument doc2 = new XWikiDocument();
        doc2.setSyntax(Syntax.PLAIN_1_0);

        assertNull(this.xwiki.getCurrentContentSyntaxId(null, getContext()));
        assertEquals("syntaxId", this.xwiki.getCurrentContentSyntaxId("syntaxId", getContext()));

        getContext().setDoc(doc1);

        assertEquals(Syntax.CREOLE_1_0.toIdString(), this.xwiki.getCurrentContentSyntaxId(null, getContext()));

        getContext().put("sdoc", doc2);

        assertEquals(Syntax.PLAIN_1_0.toIdString(), this.xwiki.getCurrentContentSyntaxId(null, getContext()));
    }

    /**
     * Check that the user validation feature works when the validation key is stored both as plain text and as a hashed
     * field.
     * 
     * @throws Exception when any exception occurs inside XWiki
     */
    public void testValidationKeyStorage() throws Exception {
        XWikiContext context = getContext();
        context.setLanguage("en");

        // Prepare the request
        Mock request = mock(XWikiRequest.class);
        request.stubs().method("getParameter").with(eq("xwikiname")).will(returnValue("TestUser"));
        request.stubs().method("getParameter").with(eq("validkey")).will(returnValue("plaintextkey"));
        context.setRequest((XWikiRequest) request.proxy());

        // Prepare the user profile
        XWikiDocument testUser = new XWikiDocument(new DocumentReference("Wiki", "XWiki", "TestUser"));
        BaseObject userObject = (BaseObject) this.xwiki.getUserClass(context).newObject(context);
        testUser.addObject("XWiki.XWikiUsers", userObject);
        this.xwiki.saveDocument(testUser, context);

        // Check with a correct plaintext key
        BaseProperty validationKey = new StringProperty();
        validationKey.setValue("plaintextkey");
        userObject.safeput("validkey", validationKey);

        assertEquals(0, this.xwiki.validateUser(false, getContext()));

        // Check with an incorrect plaintext key
        validationKey.setValue("wrong key");

        assertEquals(-1, this.xwiki.validateUser(false, getContext()));

        // Check with a correct hashed key
        validationKey = ((PropertyClass) this.xwiki.getUserClass(context).get("validkey"))
                .fromString("plaintextkey");
        assertTrue(validationKey.getValue().toString().startsWith("hash:"));
        userObject.safeput("validkey", validationKey);

        assertEquals(0, this.xwiki.validateUser(false, getContext()));

        // Check with an incorrect hashed key
        validationKey = ((PropertyClass) this.xwiki.getUserClass(context).get("validkey")).fromString("wrong key");
        assertTrue(validationKey.getValue().toString().startsWith("hash:"));
        userObject.safeput("validkey", validationKey);

        assertEquals(-1, this.xwiki.validateUser(false, getContext()));
    }
}