35530: [CVS Core] Sending timestamp in the server in wrong situation
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java
index ee803e3..373f2ec 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java
@@ -765,26 +765,25 @@
 	public void sendEntry(byte[] syncBytes, String serverTimestamp) throws CVSException {
 		connection.write("Entry "); //$NON-NLS-1$
 		if (serverTimestamp == null) {
-			connection.writeLine(syncBytes, 0, syncBytes.length);
-		} else {
-			int start = Util.getOffsetOfDelimeter(syncBytes, (byte)'/', 0, 3);
-			if (start == -1) {
-				// something is wrong with the entry line so just send it as is
-				// and let the server report the error.
-				connection.writeLine(syncBytes, 0, syncBytes.length);
-				return;
-			}
-			int end = Util.getOffsetOfDelimeter(syncBytes, (byte)'/', start + 1, 1);
-			if (end == -1) {
-				// something is wrong with the entry line so just send it as is
-				// and let the server report the error.
-				connection.writeLine(syncBytes, 0, syncBytes.length);
-				return;
-			}
-			connection.write(syncBytes, 0, start + 1);
-			connection.write(serverTimestamp);
-			connection.writeLine(syncBytes, end, syncBytes.length - end);
+			serverTimestamp = ""; //$NON-NLS-1$
 		}
+		int start = Util.getOffsetOfDelimeter(syncBytes, (byte)'/', 0, 3);
+		if (start == -1) {
+			// something is wrong with the entry line so just send it as is
+			// and let the server report the error.
+			connection.writeLine(syncBytes, 0, syncBytes.length);
+			return;
+		}
+		int end = Util.getOffsetOfDelimeter(syncBytes, (byte)'/', start + 1, 1);
+		if (end == -1) {
+			// something is wrong with the entry line so just send it as is
+			// and let the server report the error.
+			connection.writeLine(syncBytes, 0, syncBytes.length);
+			return;
+		}
+		connection.write(syncBytes, 0, start + 1);
+		connection.write(serverTimestamp);
+		connection.writeLine(syncBytes, end, syncBytes.length - end);
 	}
 
 	/**
diff --git a/tests/org.eclipse.team.tests.cvs.core/plugin.xml b/tests/org.eclipse.team.tests.cvs.core/plugin.xml
index 1a9b5ea..494f000 100644
--- a/tests/org.eclipse.team.tests.cvs.core/plugin.xml
+++ b/tests/org.eclipse.team.tests.cvs.core/plugin.xml
@@ -26,7 +26,15 @@
       <import plugin="org.eclipse.team.tests.core"/>
    </requires>
 
-
+	<!-- *************** Connection Methods **************** -->
+	<extension id="pserver" point="org.eclipse.team.cvs.core.connectionmethods">
+		<adapter>
+			<run class="org.eclipse.team.tests.ccvs.core.TestConnectionMethod">
+				<parameter name="trace" value="false" /> 
+			</run>
+		</adapter>
+	</extension>
+	
 <!-- **************** TESTS ******************* -->
    <extension
          point="org.eclipse.core.tests.harness.tests">
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/TestConnection.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/TestConnection.java
new file mode 100644
index 0000000..682c9b6
--- /dev/null
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/TestConnection.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.team.tests.ccvs.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation;
+import org.eclipse.team.internal.ccvs.core.IServerConnection;
+import org.eclipse.team.internal.ccvs.core.connection.CVSAuthenticationException;
+
+/**
+ * @author Administrator
+ *
+ * To change this generated comment go to 
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+public class TestConnection implements IServerConnection {
+
+	public static TestConnection currentConnection;
+	
+	public static List previousLines;
+	public static StringBuffer currentLine;
+	
+	
+	private ByteArrayInputStream serverResponse;
+	
+	private static final String VALID_SERVER_REQUESTS = "Valid-requests Root Valid-responses valid-requests Repository Directory Max-dotdot Static-directory Sticky Checkin-prog Update-prog Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify Questionable Case Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set Kerberos-encrypt Gssapi-encrypt Gssapi-authenticate expand-modules ci co update diff log rlog add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors init annotate rannotate noop version";
+
+	public static IServerConnection createConnection(ICVSRepositoryLocation location, String password) {
+		currentConnection = new TestConnection();
+		return currentConnection;
+	}
+	
+	public static String getLastLine() {
+		if (previousLines.isEmpty()) return null;
+		return (String)previousLines.get(previousLines.size() - 1);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.team.internal.ccvs.core.IServerConnection#open(org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	public void open(IProgressMonitor monitor) throws IOException, CVSAuthenticationException {
+		resetStreams();
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.team.internal.ccvs.core.IServerConnection#close()
+	 */
+	public void close() throws IOException {
+		resetStreams();
+	}
+
+	/**
+	 * 
+	 */
+	private void resetStreams() {
+		currentLine = new StringBuffer();
+		previousLines = new ArrayList();
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.team.internal.ccvs.core.IServerConnection#getInputStream()
+	 */
+	public InputStream getInputStream() {
+		// TODO Auto-generated method stub
+		return new InputStream() {
+			public int read() throws IOException {
+				if (serverResponse == null) {
+					throw new IOException("Not prepared to make a response");
+				} else {
+					return serverResponse.read();
+				}	
+			}
+		};
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.team.internal.ccvs.core.IServerConnection#getOutputStream()
+	 */
+	public OutputStream getOutputStream() {
+		return new OutputStream() {
+			public void write(int output) throws IOException {
+				byte b = (byte)output;
+				if (b == '\n') {
+					String sentLine = currentLine.toString();
+					previousLines.add(sentLine);
+					currentLine = new StringBuffer();
+					respondToSentLine(sentLine);
+				} else {
+					currentLine.append((char)b);
+				}
+			}
+		};
+	}
+
+	/**
+	 * @param sentLine
+	 */
+	protected void respondToSentLine(String sentLine) {
+		if (sentLine.equals("valid-requests")) {
+			serverResponse = new ByteArrayInputStream((VALID_SERVER_REQUESTS + "\nok\n").getBytes());
+		}
+	}
+
+}
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/TestConnectionMethod.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/TestConnectionMethod.java
new file mode 100644
index 0000000..d64a946
--- /dev/null
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/TestConnectionMethod.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.team.tests.ccvs.core;
+
+import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation;
+import org.eclipse.team.internal.ccvs.core.IConnectionMethod;
+import org.eclipse.team.internal.ccvs.core.IServerConnection;
+
+/**
+ * @author Administrator
+ *
+ * To change this generated comment go to 
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+public class TestConnectionMethod implements IConnectionMethod {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.team.internal.ccvs.core.IConnectionMethod#getName()
+	 */
+	public String getName() {
+		return "test";
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.team.internal.ccvs.core.IConnectionMethod#createConnection(org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation, java.lang.String)
+	 */
+	public IServerConnection createConnection(ICVSRepositoryLocation location, String password) {
+		return TestConnection.createConnection(location, password);
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.team.internal.ccvs.core.IConnectionMethod#disconnect(org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation)
+	 */
+	public void disconnect(ICVSRepositoryLocation location) {
+		// Nothing need to be done
+	}
+
+}
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/AllTestsCVSResources.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/AllTestsCVSResources.java
index dfd0037..f769c0b 100644
--- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/AllTestsCVSResources.java
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/AllTestsCVSResources.java
@@ -19,6 +19,7 @@
 		suite.addTest(ResourceSyncInfoTest.suite());
 		suite.addTest(EclipseSynchronizerTest.suite());
 		suite.addTest(EclipseFolderTest.suite());
+		suite.addTest(ResourceSyncBytesTest.suite());
     	return suite; 	
 	}	
 	
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/ResourceSyncBytesTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/ResourceSyncBytesTest.java
new file mode 100644
index 0000000..91289f0
--- /dev/null
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/ResourceSyncBytesTest.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.team.tests.ccvs.core.cvsresources;
+
+import java.text.ParseException;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
+import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation;
+import org.eclipse.team.internal.ccvs.core.client.Session;
+import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
+import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
+import org.eclipse.team.internal.ccvs.core.util.CVSDateFormatter;
+import org.eclipse.team.internal.ccvs.core.util.Util;
+import org.eclipse.team.tests.ccvs.core.CVSTestSetup;
+import org.eclipse.team.tests.ccvs.core.EclipseTest;
+import org.eclipse.team.tests.ccvs.core.TestConnection;
+
+public class ResourceSyncBytesTest extends EclipseTest {
+
+	public ResourceSyncBytesTest() {
+		super();
+	}
+
+	public ResourceSyncBytesTest(String name) {
+		super(name);
+	}
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite(ResourceSyncBytesTest.class);
+		return new CVSTestSetup(suite);
+	}
+	
+	/**
+	 * Convert the input to bytes and get the bytes in the given slot delimited by slash (/).
+	 * Only retieve the bytes in the given slot and not the rest.
+	 * @param input
+	 * @param slot
+	 * @return
+	 */
+	private byte[] getBytesForSlot(String input, int slot) {
+		return getBytesForSlot(input, slot, false /* include rest */);
+	}
+	
+	/**
+	 * Convert the input to bytes and get the bytes in the given slot delimited by slash (/).
+	 * @param input
+	 * @param slot
+	 * @return
+	 */
+	private byte[] getBytesForSlot(String input, int slot, boolean includeRest) {
+		byte[] result = Util.getBytesForSlot(input.getBytes(), (byte) '/', slot, includeRest);
+		return result;
+	}
+	
+	private void assertEqualBytes(String expected, byte[] actual) {
+		assertEquals(expected, new String(actual));
+	}
+	
+	public void testUtilGetBytesForSlot() {
+		// test success cases
+		String input = "zero/one/two";
+		assertEqualBytes("zero", getBytesForSlot(input, 0));
+		assertEqualBytes("one", getBytesForSlot(input, 1));
+		assertEqualBytes("two", getBytesForSlot(input, 2));
+		assertEqualBytes("one/two", getBytesForSlot(input, 1, true /* include rest */));
+		assertEqualBytes("", getBytesForSlot("///", 0));
+		assertEqualBytes("", getBytesForSlot("///", 1));
+		assertEqualBytes("", getBytesForSlot("///", 2));
+		assertEqualBytes("/", getBytesForSlot("///", 2, true /* include rest */));
+		
+		// test failure cases
+		input = "zero/one/two";
+		assertNull(getBytesForSlot(input, 3));
+		assertNull(getBytesForSlot(input, 4));
+		assertNull(getBytesForSlot(input, -1));
+	}
+
+	public void testSendEntry() throws CVSException, ParseException {
+		ICVSRepositoryLocation location = CVSProviderPlugin.getPlugin().getRepository(":test:user:password@host:/path");
+		// disable version detemrination to reduce traffic
+		CVSProviderPlugin.getPlugin().setDetermineVersionEnabled(false);
+		// create and open a session
+		Session session = new Session(location, CVSWorkspaceRoot.getCVSFolderFor(ResourcesPlugin.getWorkspace().getRoot()));
+		session.open(DEFAULT_MONITOR);
+		
+		// test a normal entry line
+		byte[] entryLine = "/plugin.xml/1.27/Tue Mar  4 19:47:36 2003/-ko/".getBytes();
+		session.sendEntry(entryLine, ResourceSyncInfo.getTimestampToServer(entryLine, CVSDateFormatter.entryLineToDate("Tue Mar  4 19:47:36 2003")));
+		assertEquals("Entry /plugin.xml/1.27//-ko/", TestConnection.getLastLine());
+		
+		// test a server merged with conflict entry line
+		entryLine = "/newfile.txt/1.10/Result of merge+Thu Mar 20 16:36:56 2003//".getBytes();
+		session.sendEntry(entryLine, ResourceSyncInfo.getTimestampToServer(entryLine, CVSDateFormatter.entryLineToDate("Thu Mar 20 16:36:56 2003")));
+		assertEquals("Entry /newfile.txt/1.10/+=//", TestConnection.getLastLine());
+		
+		// test a server merged entry line
+		entryLine = "/newfile.txt/1.10/Result of merge+Thu Mar 20 16:36:56 2003//".getBytes();
+		session.sendEntry(entryLine, ResourceSyncInfo.getTimestampToServer(entryLine, CVSDateFormatter.entryLineToDate("Thu Mar 20 16:37:56 2003")));
+		assertEquals("Entry /newfile.txt/1.10/+modified//", TestConnection.getLastLine());
+		
+		// test added entry line
+		entryLine = "/plugin.xml/0/dummy timestamp/-ko/".getBytes();
+		session.sendEntry(entryLine, ResourceSyncInfo.getTimestampToServer(entryLine, CVSDateFormatter.entryLineToDate("Tue Mar  4 19:47:36 2003")));
+		assertEquals("Entry /plugin.xml/0//-ko/", TestConnection.getLastLine());
+		
+		// test empty timestamp entry line
+		entryLine = "/plugin.xml/1.1//-ko/".getBytes();
+		session.sendEntry(entryLine, ResourceSyncInfo.getTimestampToServer(entryLine, CVSDateFormatter.entryLineToDate("Tue Mar  4 19:47:36 2003")));
+		assertEquals("Entry /plugin.xml/1.1//-ko/", TestConnection.getLastLine());
+		
+	}
+
+}