You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2013/08/09 17:52:34 UTC

svn commit: r1512354 - in /subversion/trunk: ./ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/src/org/apache/subversion/javahl/util/ subversion/bindings/javahl/tests/org/apach...

Author: brane
Date: Fri Aug  9 15:52:34 2013
New Revision: 1512354

URL: http://svn.apache.org/r1512354
Log:
Expose utility functions in JavaHL. Start by providing a file-based merge tool.

* build.conf (private-built-includes):
   Add org_apache_subversion_javahl_util_DiffLib.h.
  (javahl-java): Add ...javahl/util and reorder modules alphabetically.
  (javahl-callback-javah, javahl-remote-javah, javahl-callback-javah):
   Reorder modules alphabetically.
  (javahl-util-javah): New module.

* Makefile.in (javahl): Add javahl-remote-javah and javahl-util-javah.
  (doc-javahl): Add org.apache.subversion.javahl.util.

[in subversion/bindings/javahl/src/org/apache/subversion/javahl]
* SVNUtil.java: New Java class SVNUtil.
  (SVNUtil.DiffOptions): New nested class.
  (SVNUtil.ConflictDisplayStyle): New nested enumeration.
  (SVNUtil.FileMerge): New static methods.
* util/DiffLib.java: New Java class util.DiffLib.

[in subversion/bindings/javahl/native]
* org_apache_subversion_javahl_util_DiffLib.cpp:
   Native method wrappers for the util.DiffLib class.
  (Java_org_apache_subversion_javahl_util_DiffLib_nativeFileMerge):
   Native implementation of util.DiffLib.FileMerge.

[in subversion/bindings/javahl/tests/org/apache/subversion/javahl]
* UtilTests.java: New test suite for the SVNUtil class.
  (UtilTests.testFileMerge): New test case.
* RunTests.java: Add UtilTests to the test suite list.

Added:
    subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_DiffLib.cpp
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
Modified:
    subversion/trunk/Makefile.in
    subversion/trunk/build.conf
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java

Modified: subversion/trunk/Makefile.in
URL: http://svn.apache.org/viewvc/subversion/trunk/Makefile.in?rev=1512354&r1=1512353&r2=1512354&view=diff
==============================================================================
--- subversion/trunk/Makefile.in (original)
+++ subversion/trunk/Makefile.in Fri Aug  9 15:52:34 2013
@@ -460,7 +460,7 @@ revision-install:
 install-static: @INSTALL_STATIC_RULES@
 
 # JavaHL target aliases
-javahl: mkdir-init javahl-java javahl-javah javahl-callback-javah javahl-types-javah javahl-lib @JAVAHL_TESTS_TARGET@ javahl-compat
+javahl: mkdir-init javahl-java javahl-javah javahl-callback-javah javahl-remote-javah javahl-types-javah javahl-util-javah javahl-lib @JAVAHL_TESTS_TARGET@ javahl-compat
 install-javahl: javahl install-javahl-java install-javahl-javah install-javahl-lib
 javahl-compat: javahl-compat-java @JAVAHL_COMPAT_TESTS_TARGET@
 
@@ -655,9 +655,10 @@ doc-javahl:
 	  -link http://java.sun.com/javase/6/docs/api/ \
 	  org.tigris.subversion.javahl \
 	  org.apache.subversion.javahl \
-	  org.apache.subversion.javahl.remote \
 	  org.apache.subversion.javahl.callback \
-	  org.apache.subversion.javahl.types
+	  org.apache.subversion.javahl.remote \
+	  org.apache.subversion.javahl.types \
+	  org.apache.subversion.javahl.util
 
 doc-clean:
 	rm -rf $(top_srcdir)/doc/doxygen

Modified: subversion/trunk/build.conf
URL: http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1512354&r1=1512353&r2=1512354&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Fri Aug  9 15:52:34 2013
@@ -77,6 +77,7 @@ private-built-includes =
         subversion/bindings/javahl/include/org_apache_subversion_javahl_remote_CommitEditor.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_remote_StateReporter.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_ConfigImpl_Category.h
+        subversion/bindings/javahl/include/org_apache_subversion_javahl_util_DiffLib.h
 
 test-scripts =
         subversion/tests/cmdline/*_tests.py
@@ -574,8 +575,9 @@ msvc-export = ../bindings/swig/ruby/libs
 type = java
 path = subversion/bindings/javahl/src/org/apache/subversion/javahl
   subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
-  subversion/bindings/javahl/src/org/apache/subversion/javahl/types
   subversion/bindings/javahl/src/org/apache/subversion/javahl/remote
+  subversion/bindings/javahl/src/org/apache/subversion/javahl/types
+  subversion/bindings/javahl/src/org/apache/subversion/javahl/util
 src-root = subversion/bindings/javahl/src
 sources = *.java
 install = javahl-java
@@ -619,19 +621,19 @@ package-roots = org
 #add-deps = javahl-compat-java
 add-deps = $(javahl_compat_java_DEPS)
 
-[javahl-types-javah]
-type = javah 
-path = subversion/bindings/javahl/src/org/apache/subversion/javahl/types
+[javahl-callback-javah]
+type = javah
+path = subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include
-package = org.apache.subversion.javahl.types
+package = org.apache.subversion.javahl.callback
 sources = *.java
 add-deps = $(javahl_java_DEPS)
 install = javahl-javah
 link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
 
 [javahl-remote-javah]
-type = javah 
+type = javah
 path = subversion/bindings/javahl/src/org/apache/subversion/javahl/remote
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include
@@ -641,19 +643,30 @@ add-deps = $(javahl_java_DEPS)
 install = javahl-javah
 link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
 
-[javahl-callback-javah]
-type = javah 
-path = subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
+[javahl-types-javah]
+type = javah
+path = subversion/bindings/javahl/src/org/apache/subversion/javahl/types
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include
-package = org.apache.subversion.javahl.callback
+package = org.apache.subversion.javahl.types
+sources = *.java
+add-deps = $(javahl_java_DEPS)
+install = javahl-javah
+link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
+
+[javahl-util-javah]
+type = javah
+path = subversion/bindings/javahl/src/org/apache/subversion/javahl/util
+classes = subversion/bindings/javahl/classes
+headers = subversion/bindings/javahl/include
+package = org.apache.subversion.javahl.util
 sources = *.java
 add-deps = $(javahl_java_DEPS)
 install = javahl-javah
 link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
 
 [javahl-javah]
-type = javah 
+type = javah
 path = subversion/bindings/javahl/src/org/apache/subversion/javahl
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include

Added: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_DiffLib.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_DiffLib.cpp?rev=1512354&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_DiffLib.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_DiffLib.cpp Fri Aug  9 15:52:34 2013
@@ -0,0 +1,119 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file org_apache_subversion_javahl_util_DiffLib.cpp
+ * @brief Implementation of the native methods in the Java class DiffLib
+ */
+
+#include "../include/org_apache_subversion_javahl_util_DiffLib.h"
+
+#include "JNIStackElement.h"
+#include "JNIStringHolder.h"
+#include "JNIUtil.h"
+#include "OutputStream.h"
+#include "Path.h"
+#include "Pool.h"
+
+#include "svn_diff.h"
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_util_DiffLib_nativeFileMerge(
+    JNIEnv* env, jobject jthis,
+    jstring joriginal_file,
+    jstring jmodified_file,
+    jstring jlatest_file,
+
+    jint jignore_space_ordinal,
+    jboolean jignore_eol_style,
+    jboolean jshow_c_function,
+
+    jstring jconflict_original,
+    jstring jconflict_modified,
+    jstring jconflict_latest,
+    jstring jconflict_separator,
+    jint jconflict_style_ordinal,
+
+    jobject jresult_stream)
+{
+  JNIEntry(DiffLib, nativeFileMerge);
+
+  // Using a "global" request pool since we don't keep a context with
+  // its own pool around for these functions.
+  SVN::Pool pool;
+
+  Path original(joriginal_file, pool);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+  SVN_JNI_ERR(original.error_occurred(),);
+
+  Path modified(jmodified_file, pool);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+  SVN_JNI_ERR(modified.error_occurred(),);
+
+  Path latest(jlatest_file, pool);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+  SVN_JNI_ERR(latest.error_occurred(),);
+
+  svn_diff_t* diff;
+  svn_diff_file_options_t* diff_options =
+    svn_diff_file_options_create(pool.getPool());
+  diff_options->ignore_space =
+    svn_diff_file_ignore_space_t(jignore_space_ordinal);
+  diff_options->ignore_eol_style = svn_boolean_t(jignore_eol_style);
+  diff_options->show_c_function = svn_boolean_t(jshow_c_function);
+  SVN_JNI_ERR(svn_diff_file_diff3_2(&diff,
+                                    original.c_str(),
+                                    modified.c_str(),
+                                    latest.c_str(),
+                                    diff_options,
+                                    pool.getPool()),);
+
+  JNIStringHolder conflict_original(jconflict_original);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
+  JNIStringHolder conflict_modified(jconflict_modified);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
+  JNIStringHolder conflict_latest(jconflict_latest);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
+  JNIStringHolder conflict_separator(jconflict_separator);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+  
+  OutputStream result_stream(jresult_stream);
+
+  SVN_JNI_ERR(svn_diff_file_output_merge2(
+                  result_stream.getStream(pool), diff,
+                  original.c_str(), modified.c_str(), latest.c_str(),
+                  conflict_original.c_str(),
+                  conflict_modified.c_str(),
+                  conflict_latest.c_str(),
+                  conflict_separator.c_str(),
+                  svn_diff_conflict_display_style_t(jconflict_style_ordinal),
+                  pool.getPool()),);
+}

Added: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java?rev=1512354&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java (added)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java Fri Aug  9 15:52:34 2013
@@ -0,0 +1,152 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+package org.apache.subversion.javahl;
+
+import org.apache.subversion.javahl.util.*;
+
+import java.io.OutputStream;
+
+public class SVNUtil
+{
+    /**
+     * Options to control the behaviour of the file diff routines.
+     */
+    public static class DiffOptions
+    {
+        /**
+         * To what extent whitespace should be ignored when comparing lines.
+         */
+        public enum IgnoreSpace
+        {
+            /** Do not ignore whitespace */
+            none,
+
+            /**
+             * Ignore changes in sequences of whitespace characters,
+             * treating each sequence of whitespace characters as a
+             * single space.
+             */
+            change,
+
+            /** Ignore all whitespace characters. */
+            all
+        }
+
+        /**
+         * @param ignoreSpace Whether and how to ignore space differences
+         *        in the files. The default is {@link IgnoreSpace#none}.
+         * @param ignoreEolStyle Whether to treat all end-of-line
+         *        markers the same when comparing lines.  The default
+         *        is <code>false</code>.
+         * @param showCFunction Whether the "@@" lines of the unified
+         *        diff output should include a prefix of the nearest
+         *        preceding line that starts with a character that
+         *        might be the initial character of a C language
+         *        identifier. The default is <code>false</code>.
+         */
+        public DiffOptions(IgnoreSpace ignoreSpace,
+                           boolean ignoreEolStyle,
+                           boolean showCFunction)
+        {
+            this.ignoreSpace = ignoreSpace;
+            this.ignoreEolStyle = ignoreEolStyle;
+            this.showCFunction = showCFunction;
+        }
+
+        public final IgnoreSpace ignoreSpace;
+        public final boolean ignoreEolStyle;
+        public final boolean showCFunction;
+    }
+
+    /** Style for displaying conflicts in merge output. */
+    public enum ConflictDisplayStyle
+    {
+        /** Display modified and latest, with conflict markers. */
+        modified_latest,
+
+        /**
+         * Like <code>modified_latest</code>, but with an extra effort
+         * to identify common sequences between modified and latest.
+         */
+        resolved_modified_latest,
+
+        /** Display modified, original, and latest, with conflict markers. */
+        modified_original_latest,
+
+        /** Just display modified, with no markers. */
+        modified,
+
+        /** Just display latest, with no markers. */
+        latest,
+
+        /**
+         * Like <code>modified_original_latest</code>, but
+         * <em>only<em> showing conflicts.
+         */
+        only_conflicts
+    }
+
+    /**
+     * Given three versions of a file, base
+     * (<code>originalFile</code>), incoming
+     * (<code>modifiedFile</code>) and current
+     * (<code>latestFile</code>, produce a merged result, possibly
+     * displaying conflict markers.
+     *
+     * @param originalFile The base file version (common ancestor)
+     * @param modifiedFile The incoming file version (modified elsewhere)
+     * @param latestFile The current file version (modified locally)
+     * @param diffOptions Options controlling how files are compared.
+     *        May be <code>null</code>.
+     * @param conflictOriginal Optional custom conflict marker for
+     *        the <code>originalFile</code> contents.
+     * @param conflictModified Optional custom conflict marker for
+     *        the <code>modifiedFile</code> contents.
+     * @param conflictLatest Optional custom conflict marker for
+     *        the <code>latestFile</code> contents.
+     * @param conflictSeparator Optional custom conflict separator.
+     * @param conflictStyle Determines how conflicts are displayed.
+     * @param resultStream The stream that receives the merged output.
+     */
+    public static void FileMerge(String originalFile,
+                                 String modifiedFile,
+                                 String latestFile,
+                                 DiffOptions diffOptions,
+
+                                 String conflictOriginal,
+                                 String conflictModified,
+                                 String conflictLatest,
+                                 String conflictSeparator,
+                                 ConflictDisplayStyle conflictStyle,
+
+                                 OutputStream resultStream)
+        throws ClientException
+    {
+        new DiffLib().FileMerge(originalFile, modifiedFile, latestFile,
+                                diffOptions,
+                                conflictOriginal, conflictModified,
+                                conflictLatest, conflictSeparator,
+                                conflictStyle, resultStream);
+    }
+}
\ No newline at end of file

Added: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java?rev=1512354&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java (added)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/DiffLib.java Fri Aug  9 15:52:34 2013
@@ -0,0 +1,105 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+package org.apache.subversion.javahl.util;
+
+import org.apache.subversion.javahl.SVNUtil;
+import org.apache.subversion.javahl.ClientException;
+import org.apache.subversion.javahl.NativeResources;
+
+import java.io.OutputStream;
+
+/**
+ * Encapsulates utility functions provided by libsvn_diff.
+ * @since 1.9
+ */
+public class DiffLib
+{
+    /**
+     * Load the required native library.
+     */
+    static
+    {
+        NativeResources.loadNativeLibrary();
+    }
+
+    /** @see ISVNUtil.FileMerge */
+    public void FileMerge(String originalFile,
+                          String modifiedFile,
+                          String latestFile,
+                          SVNUtil.DiffOptions diffOptions,
+
+                          String conflictOriginal,
+                          String conflictModified,
+                          String conflictLatest,
+                          String conflistSeparator,
+                          SVNUtil.ConflictDisplayStyle conflictStyle,
+
+                          OutputStream resultStream)
+        throws ClientException
+    {
+        nativeFileMerge(originalFile,
+                        modifiedFile,
+                        latestFile,
+
+                        // Interpret the diff options
+                        (diffOptions == null
+                         ? SVNUtil.DiffOptions.IgnoreSpace.none.ordinal()
+                         : diffOptions.ignoreSpace.ordinal()),
+                        (diffOptions == null ? false
+                         : diffOptions.ignoreEolStyle),
+                        (diffOptions == null ? false
+                         : diffOptions.showCFunction),
+
+                        conflictOriginal,
+                        conflictModified,
+                        conflictLatest,
+                        conflistSeparator,
+
+                        // Interpret the conflict style
+                        conflictStyle.ordinal(),
+
+                        resultStream);
+    }
+
+    private native
+        void nativeFileMerge(String originalFile,
+                             String modifiedFile,
+                             String latestFile,
+
+                             // Interpreted diff options
+                             int ignoreSpace,
+                             boolean ignoreEolStyle,
+                             boolean showCFunction,
+
+                             String conflictOriginal,
+                             String conflictModified,
+                             String conflictLatest,
+                             String conflistSeparator,
+
+                             // Interpreted conflict display style
+                             int conflictStyle,
+
+                             OutputStream resultStream)
+        throws ClientException;
+}

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java?rev=1512354&r1=1512353&r2=1512354&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java Fri Aug  9 15:52:34 2013
@@ -91,9 +91,10 @@ public class RunTests
             if (testCases == null || testCases.length == 0)
             {
                 // Add default test suites.
-                suite.addTestSuite(SVNReposTests.class);
-                suite.addTestSuite(SVNRemoteTests.class);
                 suite.addTestSuite(BasicTests.class);
+                suite.addTestSuite(UtilTests.class);
+                suite.addTestSuite(SVNRemoteTests.class);
+                suite.addTestSuite(SVNReposTests.class);
             }
             else
             {

Added: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java?rev=1512354&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java (added)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java Fri Aug  9 15:52:34 2013
@@ -0,0 +1,112 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+package org.apache.subversion.javahl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+
+import org.junit.Assert;
+
+/**
+ * Tests the JavaHL SVNUtil APIs.
+ */
+public class UtilTests extends SVNTests
+{
+    /**
+     * Base name of all our tests.
+     */
+    public final static String testName = "util_test";
+
+    public UtilTests()
+    {
+        init();
+    }
+
+    public UtilTests(String name)
+    {
+        super(name);
+        init();
+    }
+
+    /**
+     * Initialize the testBaseName and the testCounter, if this is the
+     * first test of this class.
+     */
+    private void init()
+    {
+        if (!testName.equals(testBaseName))
+        {
+            testCounter = 0;
+            testBaseName = testName;
+        }
+    }
+
+    private final byte[] fileContentsPrefix = "1\n2\n3\n4".getBytes();
+    private final byte[] fileContentsSuffix = "N-3\nN-2\nN-1\nN\n".getBytes();
+
+    private void writeFileContents(File file, String contents) throws Throwable
+    {
+        FileOutputStream out = new FileOutputStream(file);
+        out.write(fileContentsPrefix);
+        out.write(contents.getBytes());
+        out.write(fileContentsSuffix);
+        out.close();
+    }
+
+    public void testFileMerge() throws Throwable
+    {
+        File original = File.createTempFile("merge", ".original", localTmp);
+        File modified = File.createTempFile("merge", ".modified", localTmp);
+        File latest = File.createTempFile("merge", ".latest", localTmp);
+
+        writeFileContents(original, "\noriginal\n");
+        writeFileContents(modified, "\nmodified\n");
+        writeFileContents(latest, "\nlatest\n");
+
+        ByteArrayOutputStream result = new ByteArrayOutputStream();
+        SVNUtil.FileMerge(original.getAbsolutePath(),
+                          modified.getAbsolutePath(),
+                          latest.getAbsolutePath(),
+                          null,
+                          "||||||| base",
+                          "<<<<<<< branch",
+                          ">>>>>>> local",
+                          "=======",
+                          SVNUtil.ConflictDisplayStyle.modified_original_latest,
+                          result);
+
+        final byte[] expected = ("1\n2\n3\n4\n" +
+                                 "<<<<<<< branch\n" +
+                                 "modified\n" +
+                                 "||||||| base\n" +
+                                 "original\n" +
+                                 "=======\n" +
+                                 "latest\n" +
+                                 ">>>>>>> local\n" +
+                                 "N-3\nN-2\nN-1\nN\n").getBytes();
+        Assert.assertArrayEquals(expected, result.toByteArray());
+    }
+}