001package org.apache.maven.scm;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.util.ArrayList;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map;
027import java.util.TreeMap;
028
029import org.apache.maven.scm.command.add.AddScmResult;
030import org.apache.maven.scm.command.checkin.CheckInScmResult;
031import org.apache.maven.scm.command.checkout.CheckOutScmResult;
032import org.apache.maven.scm.command.edit.EditScmResult;
033import org.apache.maven.scm.command.remove.RemoveScmResult;
034import org.apache.maven.scm.provider.ScmProvider;
035import org.apache.maven.scm.repository.ScmRepository;
036import org.codehaus.plexus.util.StringUtils;
037import org.junit.After;
038import org.junit.Before;
039
040import static org.junit.Assert.assertEquals;
041import static org.junit.Assert.assertTrue;
042
043import static org.junit.Assume.assumeTrue;
044
045/**
046 * Base class for all TcK tests.
047 * <p>
048 * Basically all it does is to setup a default test enviroment
049 * common for all tck tests. The default setup includes:
050 * <ol>
051 * <li>Delete all default locations (working copy, updating copy etc)</li>
052 * <li>Initialize the repository</li>
053 * <li>Check out the repository to the working copy</li>
054 * </ol>
055 *
056 * @author <a href="mailto:torbjorn@smorgrav.org">Torbj�rn Eikli Sm�rgrav</a>
057 *
058 */
059public abstract class ScmTckTestCase
060    extends ScmTestCase
061{
062    private ScmRepository scmRepository;
063
064    private List<String> scmFileNames;
065
066    /**
067     * Some tests can only run if the appropriate application has been installed.
068     * If the provided name is not a runnable application all tests in the class are skipped.
069     * @return The commandline command for the specific scm provider. Or null if none is needed.
070     */
071    public String getScmProviderCommand()
072    {
073        return null;
074    }
075
076    /**
077     * @return A provider specific and valid url for the repository
078     * @throws Exception if any
079     */
080    public abstract String getScmUrl()
081        throws Exception;
082
083    /**
084     * <p>
085     * Get the list of file names that is supposed to be in the test repo.
086     * </p>
087     * <ul>
088     * <li>/pom.xml</li>
089     * <li>/readme.txt</li>
090     * <li>/src/main/java/Application.java</li>
091     * <li>/src/test/java/Test.java</li>
092     * </ul>
093     *
094     * @return {@link List} of {@link String} objects
095     */
096    protected List<String> getScmFileNames()
097    {
098        return scmFileNames;
099    }
100
101    /**
102     * <p>
103     * Initialize repository at the {@link #getScmUrl()} location with the files in {@link #getScmFileNames()}
104     * </p>
105     * <p>
106     * The setup is also asserting on the existence of these files. <br>
107     * This should only be used by this class (thus do not call this method from derived classes)
108     * </p>
109     * <b>Note</b>: 'svnadmin' should be a system command.
110     *
111     * @throws Exception if any
112     */
113    public abstract void initRepo()
114        throws Exception;
115
116    public void checkScmPresence()
117    {
118        String scmProviderCommand = getScmProviderCommand();
119        if ( scmProviderCommand != null )
120        {
121            assumeTrue( "Skipping tests because the required command '" + scmProviderCommand + "' is not available.",
122                ScmTestCase.isSystemCmd( scmProviderCommand ) );
123        }
124    }
125
126    /**
127     * {@inheritDoc}
128     */
129    @Before
130    @Override
131    public void setUp()
132        throws Exception
133    {
134        checkScmPresence();
135        super.setUp();
136
137        scmRepository = null;
138
139        scmFileNames = new ArrayList<>( 4 );
140        scmFileNames.add( "/pom.xml" );
141        scmFileNames.add( "/readme.txt" );
142        scmFileNames.add( "/src/main/java/Application.java" );
143        scmFileNames.add( "/src/test/java/Test.java" );
144
145        initRepo();
146
147        checkOut( getWorkingCopy(), getScmRepository() );
148
149        Iterator<String> it = getScmFileNames().iterator();
150        while ( it.hasNext() )
151        {
152            assertFile( getWorkingCopy(), it.next() );
153        }
154    }
155
156    /**
157     * This method is available to those SCM clients that need to perform
158     * a cleanup at the end of the tests. It is needed when server side
159     * operations are performed, or the check out dirs are outside
160     * of the normal target directory.
161     */
162    public void removeRepo()
163        throws Exception
164    {
165    }
166
167    /**
168     * Provided to allow removeRepo() to be called.
169     */
170    @After
171    @Override
172    public void tearDown()
173        throws Exception
174    {
175        super.tearDown();
176        removeRepo();
177    }
178
179    /**
180     * Convenience method to get the ScmRepository for this provider
181     */
182    protected ScmRepository getScmRepository()
183        throws Exception
184    {
185        if ( scmRepository == null )
186        {
187            scmRepository = getScmManager().makeScmRepository( getScmUrl() );
188        }
189
190        return scmRepository;
191    }
192
193    /**
194     * Convenience method to check out files from the repository
195     */
196    protected CheckOutScmResult checkOut( File workingDirectory, ScmRepository repository )
197        throws Exception
198    {
199        CheckOutScmResult result =
200            getScmManager().getProviderByUrl( getScmUrl() ).checkOut( repository, new ScmFileSet( workingDirectory ),
201                                                                      (ScmVersion) null );
202
203        assertTrue( "Check result was successful, output: " + result.getCommandOutput(), result.isSuccess() );
204
205        return result;
206    }
207
208    /**
209     * Convenience method to check in files to the repository
210     */
211    protected CheckInScmResult checkIn( File workingDirectory, ScmRepository repository )
212        throws Exception
213    {
214        CheckInScmResult result = getScmManager().getProviderByUrl( getScmUrl() )
215            .checkIn( repository, new ScmFileSet( workingDirectory ), (ScmVersion) null, "Initial Checkin" );
216
217        assertTrue( "Check result was successful, output: " + result.getCommandOutput(), result.isSuccess() );
218
219        return result;
220    }
221
222    /**
223     * Convenience method to remove files from the repository
224     */
225    protected RemoveScmResult remove( File workingDirectory, ScmRepository repository )
226            throws Exception
227    {
228        RemoveScmResult result = getScmManager().getProviderByUrl( getScmUrl() )
229            .remove( repository, new ScmFileSet( workingDirectory ), "Initial Checkin" );
230
231        assertTrue( "Remove result was successful, output: " + result.getCommandOutput(), result.isSuccess() );
232
233        return result;
234    }
235
236    /**
237     * Convenience method to add a file to the working tree at the working directory
238     */
239    protected void addToWorkingTree( File workingDirectory, File file, ScmRepository repository )
240        throws Exception
241    {
242        ScmProvider provider = getScmManager().getProviderByUrl( getScmUrl() );
243
244        CommandParameters commandParameters = new CommandParameters();
245        commandParameters.setString( CommandParameter.FORCE_ADD, Boolean.TRUE.toString() );
246
247        AddScmResult result = provider.add( repository, new ScmFileSet( workingDirectory, file ), commandParameters );
248
249        assertTrue( "Check result was successful, output: " + result.getCommandOutput(), result.isSuccess() );
250
251        List<ScmFile> addedFiles = result.getAddedFiles();
252
253        if ( new File( workingDirectory, file.getPath() ).isFile() )
254        {
255            // Don't check directory add because some SCM tools ignore it
256            assertEquals( "Expected 1 file in the added files list " + addedFiles, 1, addedFiles.size() );
257        }
258    }
259
260    /**
261     * take the files of the given list, add them to a TreeMap and
262     * use the pathName String as key for the Map.
263     * This function is useful for every TCK which has to check for the
264     * existence of more than 1 file of the returned ScmResult, regardless
265     * of their order in the list.
266     * All backslashes in the path will be replaced by forward slashes
267     * for Windows compatibility.
268     *
269     * @param files List with {@code ScmFile}s
270     * @return Map key=pathName, value=ScmFile
271     */
272    protected Map<String, ScmFile> mapFilesByPath( List<ScmFile> files )
273    {
274        if ( files == null )
275        {
276            return null;
277        }
278
279        Map<String, ScmFile> mappedFiles = new TreeMap<>();
280        for ( ScmFile scmFile : files )
281        {
282            String path = StringUtils.replace( scmFile.getPath(), "\\", "/" );
283            mappedFiles.put( path, scmFile );
284        }
285
286        return mappedFiles;
287    }
288
289    protected EditScmResult edit( File basedir, String includes, String excludes, ScmRepository repository )
290        throws Exception
291    {
292        if ( this.getScmManager().getProviderByRepository( this.getScmRepository() ).requiresEditMode() )
293        {
294            ScmFileSet fileSet = new ScmFileSet( basedir, includes, excludes );
295            return getScmManager().edit( getScmRepository(), fileSet );
296        }
297        return new EditScmResult( "", "", "", true );
298    }
299
300}