/* * P4.Net * Copyright (c) 2007-2010 Shawn Hladky Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; using NUnit.Framework; using P4API; using System.IO; using System.Threading; using System.Diagnostics; namespace P4.Net.TestDriver { /// Some simple Tests. /// [TestFixture] public class StandardTest { private P4Connection p4 = null; private string p4ClientRootDirectory = null; private string p4ClientRootDirectory2 = null; public static ManualResetEvent mre = new ManualResetEvent(false); public static ManualResetEvent mre2 = new ManualResetEvent(false); private int onResolveCount; private string _testPort = "5791"; private string _user1 = "TestUser1"; private const string _client1 = "TestClient1"; private TraceListener consoleListner; [Test] public void Test001_SetupConnection() { consoleListner = new ConsoleTraceListener(); consoleListner.Name = "myConsoleListner"; Trace.Listeners.Add(consoleListner); Trace.WriteLine("shawn was here."); p4 = new P4Connection(); p4.Port = _testPort; p4.CallingProgram = "P4.Net Test Harness"; p4.CallingVersion = "1.0"; p4.Connect(); p4.Client = _client1; p4.User = _user1; P4Record s = p4.Run("info")[0]; Assert.AreEqual(s["userName"], "*unknown*", "User name should be *unknown*. This test requires an empty repository"); Assert.AreEqual(s["clientName"], "*unknown*", "Client spec should be *unknown*. This test requires an empty repository"); } [Test] public void Test002_CreateClient() { p4ClientRootDirectory = Path.Combine(Path.GetTempPath(), "p4temproot"); if (Directory.Exists(p4ClientRootDirectory)) { // what to do??? } else { Directory.CreateDirectory(p4ClientRootDirectory); } P4Form client = p4.Fetch_Form("client"); //test the indexer client["Root"] = p4ClientRootDirectory; //test the Fields collection client.Fields["Description"] = "Created from unit test"; //Test setting an array string[] view = { @"//depot/... //TestClient1/..." }; client.ArrayFields["View"] = view; P4UnParsedRecordSet result = p4.Save_Form(client); Assert.AreEqual(result.Messages.Length, 1, "While saving client spec, unexpected number of messages"); Assert.AreEqual(result[0], "Client TestClient1 saved.", "Unable to save client spec"); //now lets pull the form again and verify values client = p4.Fetch_Form("client"); Assert.AreEqual(client["Root"], p4ClientRootDirectory, "Unexpected client root."); Assert.AreEqual(client.Fields["Description"], "Created from unit test\n", "Unexpected client description."); Assert.AreEqual(client.ArrayFields["View"].Length, 1, "Unexpected client view."); // lets save this with a new name client["Client"] = "TestClient2"; // now, lets test the view as a multi-valued array // yes, I know this is a dumb view string[] view2 = { @"//depot/shawn/... //TestClient2/shawn2/...", @"//depot/shawn/a/... //TestClient2/shawn/a/...", @"//depot/shawn/b/... //TestClient2/shawn/b/...", @"//depot/shawn/c/... //TestClient2/shawn/c/...", @"//depot/shawn/d/... //TestClient2/shawn/d/...", @"//depot/shawn/e/... //TestClient2/shawn/e/...", @"//depot/shawn/f/... //TestClient2/shawn/f/...", @"//depot/shawn/g/... //TestClient2/shawn/g/...", @"//depot/shawn/h/... //TestClient2/shawn/h/...", @"//depot/shawn/i/... //TestClient2/shawn/i/...", @"//depot/shawn/j/... //TestClient2/shawn/j/...", @"//depot/shawn/k/... //TestClient2/shawn/k/...", @"//depot/shawn/l/... //TestClient2/shawn/l/...", @"//depot/shawn/m/... //TestClient2/shawn/m/..."}; client.ArrayFields["View"] = view2; result = p4.Save_Form(client); Assert.AreEqual(result.Messages.Length, 1, "While saving client spec, unexpected number of messages"); Assert.AreEqual(result[0], "Client TestClient2 saved.", "Unable to save client spec"); //now lets pull the form again and verify values client = p4.Fetch_Form("client", "TestClient2"); Assert.AreEqual(client.ArrayFields["View"].Length, 14, "Unexpected client view."); } [Test] public void Test003_AddFiles() { string testPath = Path.Combine(p4ClientRootDirectory, "test003"); //Create some test files Directory.CreateDirectory(testPath); P4PendingChangelist cl = p4.CreatePendingChangelist("Test003"); string[] args = new string[12]; args[0] = "-c"; args[1] = cl.Number.ToString(); for (int i = 0; i < 10; i++) { string fn = string.Format("File{0}", i); StreamWriter sw = File.CreateText(Path.Combine(testPath, fn)); sw.WriteLine("this is file: {0}", fn); sw.Close(); args[i + 2] = Path.Combine(testPath, fn); } P4UnParsedRecordSet r = p4.RunUnParsed("add", args); Assert.AreEqual(r.Messages.Length, 10, "Invalid response from p4 add"); for (int i = 0; i < 10; i++) { Assert.AreEqual(string.Format("//depot/test003/File{0}#1 - opened for add", i), r.Messages[i], "Invalid response from p4 add"); } r = cl.Submit(); Assert.AreEqual("Submitting change 1.", r.Messages[0], "Unexpected output from p4 submit"); } [Test] public void Test004_IntegFiles() { //Trace.WriteLine("Before pending."); P4PendingChangelist cl = p4.CreatePendingChangelist("Test004"); //Trace.WriteLine("Before integ."); P4UnParsedRecordSet r = p4.RunUnParsed("integ", "-c", cl.Number.ToString(), "//depot/test003/...", "//depot/test004/..."); Assert.AreEqual(r.Messages.Length, 10, "Invalid response from p4 add"); for (int i = 0; i < 10; i++) { Assert.AreEqual(string.Format("//depot/test004/File{0}#1 - branch/sync from //depot/test003/File{0}#1", i), r.Messages[i], "Invalid response from p4 add"); } //Trace.WriteLine("Before submit."); r = cl.Submit(); Assert.AreEqual("Submitting change 2.", r.Messages[0], "Unexpected output from p4 submit"); } [Test] public void Test005_EditFiles() { string testPath = Path.Combine(p4ClientRootDirectory, "test003"); P4PendingChangelist cl = p4.CreatePendingChangelist("Test005"); // Add lines to a file P4UnParsedRecordSet r = p4.RunUnParsed("edit", "-c", cl.Number.ToString(), "//depot/test003/File0"); string fn = Path.Combine(testPath, "File0"); StreamWriter sw = File.AppendText(fn); sw.WriteLine("Line 2", fn); sw.WriteLine("Line 3", fn); sw.WriteLine("Line 4", fn); sw.Close(); //Modify a line r = p4.RunUnParsed("edit", "-c", cl.Number.ToString(), "//depot/test003/File1"); fn = Path.Combine(testPath, "File1"); sw = File.CreateText(fn); sw.WriteLine("Modified File1", fn); sw.Close(); //Delete a file r = p4.RunUnParsed("delete", "-c", cl.Number.ToString(), "//depot/test003/File2"); r = cl.Submit(); Assert.AreEqual("Submitting change 3.", r.Messages[0], "Unexpected output from p4 submit"); } [Test] public void Test006_Password() { string testPath = Path.Combine(p4ClientRootDirectory, "test003"); p4.OnPrompt += new OnPromptEventHandler(OnPrompt); try { //change the password P4UnParsedRecordSet r = p4.RunUnParsed("passwd"); //now login p4.Login("password"); } catch (Exception e) { Assert.Fail(e.Message); } } [Test] [ExpectedException(typeof(P4API.Exceptions.RunException))] public void Test007_WarningLevels() { p4.ExceptionLevel = P4ExceptionLevels.ExceptionOnBothErrorsAndWarnings; p4.Run("sync"); } [Test] public void Test008_WarningLevels() { p4.ExceptionLevel = P4ExceptionLevels.NoExceptionOnWarnings; P4RecordSet r = p4.Run("sync"); Assert.AreEqual(r.Warnings[0], "File(s) up-to-date."); P4UnParsedRecordSet r2 = p4.RunUnParsed("sync"); Assert.AreEqual(r2.Warnings[0], "File(s) up-to-date."); } [Test] [ExpectedException(typeof(P4API.Exceptions.RunException))] public void Test009_WarningLevels() { p4.ExceptionLevel = P4ExceptionLevels.NoExceptionOnWarnings; P4RecordSet r = p4.Run("bogus"); } [Test] public void Test010_WarningLevels() { p4.ExceptionLevel = P4ExceptionLevels.NoExceptionOnErrors; P4UnParsedRecordSet r = p4.RunUnParsed("bogus"); Assert.AreEqual(r.Errors[0], "Unknown command. Try 'p4 help' for info."); P4RecordSet r2 = p4.Run("bogus"); Assert.AreEqual(r2.Errors[0], "Unknown command. Try 'p4 help' for info."); } [Test] public void Test011_DateConversions() { DateTime res = p4.ConvertDate("1159361459"); DateTime ans = new DateTime(2006, 9, 27, 6, 50, 59); Assert.AreEqual(res, ans); int tics = p4.ConvertDate(ans); Assert.AreEqual(tics, 1159361459); } ////[Test] //public void Test012_DroppedConnection() //{ // System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(RunOnNewThread)); // t.Start(); // mre.WaitOne(); // Thread.Sleep(100); // Console.WriteLine("ready for some football"); // //find the PID and kill the new connection // P4RecordSet monitor = p4.Run("monitor", "show", "-ale"); // foreach (P4Record r in monitor) // { // if (r["command"] == "login") // { // P4UnParsedRecordSet s = p4.RunUnParsed("monitor", "terminate", r["id"]); // Console.WriteLine(s.Messages[0]); // } // } // mre2.WaitOne(); //} [Test] public void Test013_RecordsetReporting() { string s = ""; P4RecordSet fstat = p4.Run("filelog", "//..."); foreach (P4Record r in fstat) { foreach (string k in r.Fields.Keys) { s = string.Format("{0} : {1}", k, r[k]); //Console.WriteLine(s); } foreach (string k in r.ArrayFields.Keys) { for (int i = 0; i < r.ArrayFields[k].Length; i++) { s = string.Format("... {0}.{1} : {2}", k, i, r.ArrayFields[k][i]); //Console.WriteLine(s); } } } } [Test] public void Test014_AddInternationalFiles() { string testPath = Path.Combine(p4ClientRootDirectory, "español"); //Create some test files Directory.CreateDirectory(testPath); P4PendingChangelist cl = p4.CreatePendingChangelist("español"); string[] args = new string[13]; args[0] = "-c"; args[1] = cl.Number.ToString(); args[2] = "-tunicode"; for (int i = 0; i < 10; i++) { string fn = string.Format("LatinoaméricaFile{0}", i); StreamWriter sw = File.CreateText(Path.Combine(testPath, fn)); sw.WriteLine("this is file: {0}\nEn español.\nΚαλημέρα κόσμε\nこんにちは 世界", fn); sw.Close(); args[i + 3] = Path.Combine(testPath, fn); } P4UnParsedRecordSet r = p4.RunUnParsed("add", args); Assert.AreEqual(r.Messages.Length, 10, "Invalid response from p4 add"); for (int i = 0; i < 10; i++) { Assert.AreEqual(string.Format("//depot/español/LatinoaméricaFile{0}#1 - opened for add", i), r.Messages[i], "Invalid response from p4 add"); } r = cl.Submit(); Assert.AreEqual("Submitting change 4.", r.Messages[0], "Unexpected output from p4 submit"); } [Test] public void Test015_PrintStreams() { //PrintHelper ph = new PrintHelper(p4); //string s = ph.PrintTextFile("//depot/español/LatinoaméricaFile1"); string s = p4.PrintText("//depot/test003/File1"); Assert.AreEqual("Modified File1\n", s, "Print output failed."); s = p4.PrintText("//depot/español/LatinoaméricaFile1"); Assert.AreEqual("this is file: LatinoaméricaFile1\nEn español.\nΚαλημέρα κόσμε\nこんにちは 世界\n", s, "International print output failed."); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test016_BugMemoryExceptionOnNullArgumentToRun() { //someone's trying to hack p4.... p4.Run("changes", null, "-m1"); } [Test] [ExpectedException(typeof(P4API.Exceptions.FileNotFound))] public void Test017_PrintNonExistantFile() { string s = p4.PrintText("//depot/bogus.file"); Assert.AreEqual("", s, "Print of non-existance file."); } [Test] public void Test018_FormatSpec() { P4Form job = p4.Fetch_Form("job"); job["Description"] = "Quality is Job Number 1.\n"; string s = job.FormatSpec(); P4Form job2 = p4.Parse_Form("job", s); Assert.AreEqual(job["Description"], job2["Description"]); job["Description"] = "Quality is Job Number 2.\n"; s = job.FormatSpec(); P4Form job3 = p4.Parse_Form("job", s); Assert.AreEqual(job["Description"], job3["Description"]); } [Test] [ExpectedException(typeof(P4API.Exceptions.FormParseException))] public void Test019_BadSpec() { P4Form job = p4.Fetch_Form("job"); job["Description"] = "Quality is Job Number 1."; job["Status"] = "bogus"; string s = job.FormatSpec(); // should throw an exception P4Form job2 = p4.Parse_Form("job", s); } // Bug fix. Can't clobber writable files is not reporting in the errors collection [Test] public void Test020_BugCantClobberReportError() { p4.ExceptionLevel = P4ExceptionLevels.NoExceptionOnErrors; string testPath = Path.Combine(p4ClientRootDirectory, "test003"); string fn = Path.Combine(testPath, "File0"); //clear the read-only flag File.SetAttributes(fn, FileAttributes.Normal); // run a flush so it will try to sync p4.Run("flush", string.Format("{0}#1", fn)); //now run the sync P4RecordSet rs = p4.Run("sync", fn); string[] errors = { string.Format("Can't clobber writable file {0}", fn) }; Assert.AreEqual(errors, rs.Errors); } // Bug, attempting to merge a file (OnPrompt from a resolve command, and return "m" // resulted in an infinite loop. For now, we throw an exception [Test] [ExpectedException(typeof(P4API.Exceptions.MergeNotImplemented))] public void Test021_BugMergeFile() { string testPath = Path.Combine(p4ClientRootDirectory, "test003"); string fn = Path.Combine(testPath, "File0"); P4PendingChangelist cl = p4.CreatePendingChangelist("resolve test"); // This file was synced to a previous rev in another test P4RecordSet rs = p4.Run("edit", "-c", cl.Number.ToString(), fn); //foreach (string w in rs.Warnings) Console.WriteLine("W: " + w); //foreach (string m in rs.Messages) Console.WriteLine("M: " + m); //foreach (string e in rs.Errors) Console.WriteLine("E: " + e); StreamWriter sw = File.AppendText(fn); sw.WriteLine("Resolve Me 2", fn); sw.WriteLine("Resolve Me 3", fn); sw.WriteLine("Resolve Me 4", fn); sw.Close(); //now run the sync rs = p4.Run("sync", fn); //foreach (string w in rs.Warnings) Console.WriteLine("W: " + w); //foreach (string m in rs.Messages) Console.WriteLine("M: " + m); //foreach (string e in rs.Errors) Console.WriteLine("E: " + e); //TODO -- not woking yet, so this is commented ! if (p4.ServerLevel < 21) { Assert.Fail("\nServers earlier than 2006.1 always fail this test!"); } onResolveCount = 0; OnPromptEventHandler eh = new OnPromptEventHandler(OnResolvePromptMerge); p4.OnPrompt += eh; // now run a resolve... what happens? P4UnParsedRecordSet urs = p4.RunUnParsed("resolve", fn); //foreach (string w in urs.Warnings) Console.WriteLine("W: " + w); //foreach (string m in urs.Messages) Console.WriteLine("M: " + m); //foreach (string e in urs.Errors) Console.WriteLine("E: " + e); p4.OnPrompt -= eh; Console.WriteLine(onResolveCount); } // Diff... test diff output [Test] public void Test022_DiffFiles() { string testPath = Path.Combine(p4ClientRootDirectory, "test003"); string fn = Path.Combine(testPath, "File0"); P4RecordSet rs = p4.Run("diff", fn); //foreach (string w in rs.Warnings) Console.WriteLine("W: " + w); //foreach (string m in rs.Messages) Console.WriteLine("M: " + m); //foreach (string e in rs.Errors) Console.WriteLine("E: " + e); string[] e ={ "4a5,7", "> Resolve Me 2", "> Resolve Me 3", "> Resolve Me 4" }; Assert.AreEqual(e, rs.Messages); } [Test] [ExpectedException(typeof(P4API.Exceptions.FormFetchException))] public void Test023_BadFormCommand() { P4Form bs = p4.Fetch_Form("info"); } [Test] [ExpectedException(typeof(P4API.Exceptions.FormFetchException))] public void Test024_BadFormCommand() { P4Form bs = p4.Fetch_Form("bogus"); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test025_BadArguments() { P4Form bs = p4.Fetch_Form("change", null); } [Test] public void Test026_BadArguments() { P4Form bs = p4.Fetch_Form("change", ""); //P4 API just ignores the empty string //What's it look like? //Console.WriteLine(bs.FormatSpec()); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test027_BadArguments() { P4RecordSet bs = p4.Run("sync", null); } [Test] public void Test028_BadArguments() { P4RecordSet bs = p4.Run("sync", "", "-f", "//..."); //empty string causes a perforce error Assert.AreEqual(2, bs.Errors.Length); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test029_BadArguments() { P4PendingChangelist bs = p4.CreatePendingChangelist(null); } [Test] [ExpectedException(typeof(ArgumentException))] public void Test030_BadArguments() { P4PendingChangelist bs = p4.CreatePendingChangelist(""); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test031_BadArguments() { // should do nothing p4.Login(""); // this one raises the exception p4.Login(null); } [Test] public void Test032_RevertPropertiesToEnvironment() { string oldClient = p4.Client; p4.Client = ""; //Client will revert to the environment... don't know an easy way to automate that test //Console.WriteLine(p4.Client); // set it back p4.Client = oldClient; } [Test] public void Test033_BadArguments() { // what happens when I do this? p4.CWD = @"o:\bogus"; //doesn't matter to Perforce if the path doesn't exist, so I won't throw an exception either. } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test034_BadArguments() { p4.PrintStream(null, "//depot/whocares.txt"); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test035_BadArguments() { string localPath = Path.GetTempFileName(); FileStream s = new FileStream(localPath, FileMode.Create); p4.PrintStream(s, null); s.Close(); } [Test] [ExpectedException(typeof(ArgumentException))] public void Test036_BadArguments() { string localPath = Path.GetTempFileName(); FileStream s = new FileStream(localPath, FileMode.Create); p4.PrintStream(s, ""); s.Close(); } // Bug, diff2 returns tagged results that end in an integer (i.e. depotFile and depotFile2) // P4Record should show this as two keys in the Fields dictionary, but it's not. // The logic that was testing it to be an array, correctly identified it // as not being an array, but did not put them in the fields collection either [Test] public void Test037_BugDiff2FieldsLost() { P4RecordSet diff2 = p4.Run("diff2", "//depot/test003/File1#1", "//depot/test003/File1#2"); // should only be one record Assert.AreEqual(1, diff2.Records.Length); P4Record d2 = diff2[0]; Assert.AreEqual("content", d2["status"]); Assert.AreEqual("text", d2["type"]); Assert.AreEqual("1", d2["rev"]); Assert.AreEqual("2", d2["rev2"]); Assert.AreEqual("//depot/test003/File1", d2["depotFile"]); Assert.AreEqual("//depot/test003/File1", d2["depotFile2"]); // make sure nothing is trapped as an arrayfield Assert.AreEqual(0, d2.ArrayFields.Count); //foreach(P4Record d2 in diff2) //{ // foreach(string s in d2.Fields.Keys) // { // Console.WriteLine(string.Format("{0} : {1}", s, d2[s])); // } //} } [Test] public void Test038_ParseBranchSpec() { string branchSpec = @" Branch: bogus_branch Owner: shawnh Description: Created by P4.Net Options: unlocked View: //depot/test003/a/... //depot/test038/a/... //depot/test003/b/... //depot/test038/b/... "; P4Form branch = p4.Parse_Form("branch", branchSpec); Assert.AreEqual("bogus_branch", branch["Branch"]); string[] view = { "//depot/test003/a/... //depot/test038/a/...", "//depot/test003/b/... //depot/test038/b/..." }; Assert.AreEqual(view, branch.ArrayFields["View"]); //foreach (string s in branch.Fields.Keys) //{ // Console.WriteLine(string.Format("{0} : {1}", s, branch[s])); //} } [Test] public void Test039_ServerCaseSensitivity() { // since we fired this test off from a NT machine, // we know the server is case insinsitive. // the other test case needs to be run manually against a unix server Assert.AreEqual(false, p4.IsServerCaseSensitive()); } // this test will fail if the user can not connect to the Perforce public depot [Test] public void Test039_ServerCaseSensitivityPublicDepot() { P4Connection pub = new P4Connection(); pub.Port = "public.perforce.com:1666"; pub.Connect(); Assert.AreEqual(true, pub.IsServerCaseSensitive()); pub.Disconnect(); } [Test] public void Test040_PermittedFields() { P4Form job = p4.Fetch_Form("job"); string[] result = { "Job", "Status", "User", "Date", "Description" }; Assert.AreEqual(true, job.PermittedFields.Contains("Job")); Assert.AreEqual(true, job.PermittedFields.Contains("Status")); Assert.AreEqual(true, job.PermittedFields.Contains("User")); Assert.AreEqual(true, job.PermittedFields.Contains("Date")); Assert.AreEqual(true, job.PermittedFields.Contains("Description")); Assert.AreEqual(false, job.PermittedFields.Contains("job")); Assert.AreEqual(false, job.PermittedFields.Contains("bogus")); } [Test] [ExpectedException(typeof(P4API.Exceptions.FormCommandException))] public void Test041_FormCommandException() { // run a form command w/o -o or -i p4.Run("client"); } [Test] [ExpectedException(typeof(P4API.Exceptions.FormCommandException))] public void Test042_FormCommandException() { // run a form command w/o -o or -i p4.RunUnParsed("client"); } [Test] [ExpectedException(typeof(ArgumentException))] public void Test043_BadArguments() { p4.PrintBinary(""); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void Test044_BadArguments() { p4.PrintText(null); } [Test] public void Test045_OtherAction() { // need to create a file with multiple checkouts // first create another client, sync a file, and open for edit p4.Client = "TestClient3"; p4ClientRootDirectory2 = Path.Combine(Path.GetTempPath(), "p4temproot2"); if (Directory.Exists(p4ClientRootDirectory2)) { // what to do??? } else { Directory.CreateDirectory(p4ClientRootDirectory2); } P4Form client = p4.Fetch_Form("client"); //test the indexer client["Root"] = p4ClientRootDirectory2; P4UnParsedRecordSet rs = p4.Save_Form(client); //Console.WriteLine(rs.ErrorMessage); p4.Run("sync", "//depot/test003/File1"); p4.Run("edit", "//depot/test003/File1"); // change back to TestClient1 p4.Client = _client1; p4.Run("sync", "//depot/test003/File1"); p4.Run("edit", "//depot/test003/File1"); P4RecordSet fstat = p4.Run("fstat", "//depot/test003/File1"); // should be an otherOpen in the fields AND array fields Assert.AreEqual("1", fstat[0]["otherOpen"]); Assert.AreEqual("TestUser1@TestClient3", fstat[0].ArrayFields["otherOpen"][0]); //foreach (P4Record r in fstat) //{ // foreach (string k in r.Fields.Keys) // { // s = string.Format("{0} : {1}", k, r[k]); // Console.WriteLine(s); // } // foreach (string k in r.ArrayFields.Keys) // { // for (int i = 0; i < r.ArrayFields[k].Length; i++) // { // s = string.Format("... {0}.{1} : {2}", k, i, r.ArrayFields[k][i]); // Console.WriteLine(s); // } // } //} ////now } //depot/test003/File2 [Test] public void Test046_FileLogFilesize() { P4RecordSet rs = p4.Run("filelog", "//depot/test003/File2"); string[] result = { "", "20" }; Assert.AreEqual(result, rs[0].ArrayFields["fileSize"]); } // these aren't easy to test, but at least ensure they don't raise an exception [Test] public void Test047_MaxScanRows() { P4Connection p4Con = new P4Connection(); p4Con.Port = _testPort; p4Con.CallingProgram = "P4.Net Test Harness"; p4Con.CallingVersion = "1.0"; p4Con.Client = _client1; p4Con.User = _user1; p4Con.MaxResults = 10; p4Con.Connect(); P4RecordSet rs = p4Con.Run("filelog", "//..."); //Console.WriteLine(rs.ErrorMessage); p4Con.Disconnect(); } [Test] public void Test048_MaxResults() { P4Connection p4Con = new P4Connection(); p4Con.Port = _testPort; p4Con.CallingProgram = "P4.Net Test Harness"; p4Con.CallingVersion = "1.0"; p4Con.Client = _client1; p4Con.User = _user1; p4Con.MaxScanRows = 10; p4Con.Connect(); P4RecordSet rs = p4Con.Run("filelog", "//..."); //Console.WriteLine(rs.ErrorMessage); p4Con.Disconnect(); } [Test] public void Test049_MaxLockTime() { P4Connection p4Con = new P4Connection(); p4Con.Port = _testPort; p4Con.CallingProgram = "P4.Net Test Harness"; p4Con.CallingVersion = "1.0"; p4Con.Client = _client1; p4Con.User = _user1; p4Con.MaxLockTime = 10; p4Con.Connect(); P4RecordSet rs = p4Con.Run("filelog", "//..."); //Console.WriteLine(rs.ErrorMessage); p4Con.Disconnect(); } [Test] public void Test050_PrintBinary() { byte[] x = { 0x12, 0x55, 0xA4, 0xF9, 0x3A, 0x10, 0x00, 0xC4 }; string filePath = Path.Combine(this.p4ClientRootDirectory, "File1.bin"); System.IO.FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate); fs.Write(x, 0, x.Length); fs.Close(); P4PendingChangelist cl = p4.CreatePendingChangelist("Test050"); P4RecordSet rs = p4.Run("add", "-c", cl.Number.ToString(), "-tbinary", filePath); cl.Submit(); byte[] pX = p4.PrintBinary(filePath); Assert.AreEqual(x, pX); } [Test] public void Test051_UnparsedForms() { // run parsed/unparsed sequences to make sure the specstring and tagged protocol don't // step on one/another. P4UnParsedRecordSet urs = p4.RunUnParsed("client", "-o"); //Console.WriteLine(urs.Messages[0]); Assert.AreEqual(1,urs.Messages.Length); P4RecordSet rs = p4.Run("client", "-o"); //Console.WriteLine(urs.Messages[0]); Assert.AreEqual(0, rs.Messages.Length); Assert.Contains("Client", rs.Records[0].Fields.Keys); urs = p4.RunUnParsed("client", "-o"); //Console.WriteLine(urs.Messages[0]); Assert.AreEqual(1, urs.Messages.Length); rs = p4.Run("client", "-o"); //Console.WriteLine(urs.Messages[0]); Assert.AreEqual(0, rs.Messages.Length); Assert.Contains("Client", rs.Records[0].Fields.Keys); } [Test] public void Test052_BigFilePrint() { string filePath = Path.Combine(this.p4ClientRootDirectory, "File1.big"); System.IO.StreamWriter sw = new StreamWriter(filePath); int i = 0; for (i = 0; i < 1000; i++) { sw.WriteLine("shawn was here"); } sw.Close(); P4PendingChangelist cl = p4.CreatePendingChangelist("Test052"); P4RecordSet rs = p4.Run("add", "-c", cl.Number.ToString(), filePath); cl.Submit(); P4UnParsedRecordSet urs = p4.RunUnParsed("print", "-q", filePath); // messages are chunked Assert.AreEqual(5, urs.Messages.Length); string s = p4.PrintText(filePath); StringReader sr = new StringReader(s); Assert.AreEqual(1001, sr.ReadToEnd().Split('\n').Length); sr.Close(); } // Bug, diff2 looses the context diff in unparsed mode [Test] public void Test053_BugDiff2DiffsLost() { P4UnParsedRecordSet diff2 = p4.RunUnParsed("diff2", "-dbc", "//depot/test003/File1#1", "//depot/test003/File1#2"); string[] DesiredResult = {@"==== //depot/test003/File1#1 (text) - //depot/test003/File1#2 (text) ==== content", "***************\n*** 1,1 ****\n! this is file: File1\n--- 1,1 ----\n! Modified File1\n", ""}; Assert.AreEqual(DesiredResult, diff2.Messages); } [Test] public void Test054_ApiVersions() { using (P4Connection myp4 = new P4Connection()) { myp4.Port = _testPort; myp4.User = _user1; // set to a lower API level myp4.Api = 55; myp4.Connect(); P4RecordSet rs1 = myp4.Run("info"); Assert.AreEqual("User name: TestUser1", rs1.Messages[0]); // reset to normal API levels myp4.Disconnect(); myp4.Api = 58; myp4.Connect(); P4RecordSet rs2 = myp4.Run("info"); Assert.AreEqual(_user1, rs2[0]["userName"]); } } [Test] public void Test055_ChangePortAfterConnected() { p4.Disconnect(); p4.Port = _testPort; p4.Connect(); P4RecordSet rs2 = p4.Run("info"); Assert.AreEqual(_user1, rs2[0]["userName"]); } [Test] [ExpectedException(typeof(P4API.Exceptions.ServerAlreadyConnected))] public void Test056_ChangePortWithoutDisconnect() { p4.Port = _testPort; P4RecordSet rs2 = p4.Run("info"); Assert.AreEqual(_user1, rs2[0]["userName"]); } // Run an external merge tool //[Test] //public void Test057_MergeFileRunMergeTool() //{ // string testPath = Path.Combine(p4ClientRootDirectory, "test003"); // string fn = Path.Combine(testPath, "File0"); // P4RecordSet rs = p4.Run("revert", fn); // // run a flush so it will try to sync // p4.Run("flush", string.Format("{0}#1", fn)); // P4PendingChangelist cl = p4.CreatePendingChangelist("resolve test"); // p4.RunMergeTool = true; // // This file was synced to a previous rev in another test // rs = p4.Run("edit", "-c", cl.Number.ToString(), fn); // StreamWriter sw = File.AppendText(fn); // sw.WriteLine("Resolve Me 2", fn); // sw.WriteLine("Resolve Me 3", fn); // sw.WriteLine("Resolve Me 4", fn); // sw.Close(); // //now run the sync // rs = p4.Run("sync", fn); // onResolveCount = 0; // OnPromptEventHandler eh = new OnPromptEventHandler(OnResolveRunMergeTool); // p4.OnPrompt += eh; // // now run a resolve... what happens? // P4UnParsedRecordSet urs = p4.RunUnParsed("resolve", fn); // // will execute P4MERGE command now; // p4.OnPrompt -= eh; // Console.WriteLine(onResolveCount); //} // Test a different ticket file [Test] public void Test058_SetTicketFile() { string ticketFile = Path.Combine(Path.GetTempPath(), "tmpticket.txt"); p4.TicketFile = ticketFile; p4.Run("logout"); // running a login should create the new ticket file p4.Login("password"); if (!File.Exists(ticketFile)) { Assert.Fail("Ticket file not generated!"); } else { // clear the read-only flag and delete the file File.SetAttributes(ticketFile, FileAttributes.Normal); File.Delete(ticketFile); } p4.TicketFile = ""; } // Test the silent reconect "feature" [Test] public void Test059_SilentReconnect() { p4.Disconnect(); // ConvertDate was reported to be a problem after a Disconnect in 0.9 // this shouldn't be true in 1.0 since ConvertDate no longer makes a server call // and it shouldn't be a problem for any command DateTime res = p4.ConvertDate("1159361459"); DateTime ans = new DateTime(2006, 9, 27, 6, 50, 59); Assert.AreEqual(res, ans); // this one should silently reconnect. P4RecordSet rs = p4.Run("users"); Assert.AreEqual(2, rs.Records.Length); } // Parse a form without making a server connection. [Test] public void Test060_ParseRawForm() { // pull a bogus form to find the specdef P4Form b1 = p4.Fetch_Form("branch", "bogus-branch"); string specdef = b1.SpecDef; string branchSpec = @" Branch: bogus_branch Owner: shawnh Description: Created by P4.Net Options: unlocked View: //depot/test003/a/... //depot/test038/a/... //depot/test003/b/... //depot/test038/b/... "; P4Form branch = P4Form.LoadFromSpec("branch", specdef, branchSpec, System.Text.Encoding.GetEncoding(1253)); Assert.AreEqual("bogus_branch", branch["Branch"]); string[] view = { "//depot/test003/a/... //depot/test038/a/...", "//depot/test003/b/... //depot/test038/b/..." }; Assert.AreEqual(view, branch.ArrayFields["View"]); } // Test the silent reconect "feature" [Test] public void Test061_BugSilentReconnectFetch_Form() { P4Connection myp4 = new P4Connection(); myp4.Port = _testPort; myp4.Client = _client1; myp4.User = _user1; //myp4.Connect(); P4Form job = myp4.Fetch_Form("job"); myp4.Disconnect(); } #region Not calling Disconnect Tests /* * The following tests fail. I attempted to add finalizers to P4Connection * that handle the case when the end user doesn't call Disconnect(). * However there are still some lingering issues that don't allow * P4Connection to be garbage collected. So for now we punt. * [Test] public void Test062_ConvertDateNoConnect() { P4Connection myp4 = new P4Connection()); DateTime res = myp4.ConvertDate("1159361459"); DateTime ans = new DateTime(2006, 9, 27, 6, 50, 59); Assert.AreEqual(res, ans); } // prior to a fix, Connecting, doing nothing else, and failing to disconnect // would cause a memory access violation. [Test] public void Test062_NoDisconnect() { P4Connection myp4 = new P4Connection(); myp4.Port = _testPort; myp4.Client = _client1; myp4.User = _user1; myp4.Connect(); //P4Form job = myp4.Fetch_Form("job"); //myp4.Disconnect(); } // prior to a fix, nUnit would hang if you didn't disconnect() [Test] public void Test063_NoDisconnect() { P4Connection myp4 = new P4Connection(); myp4.Port = _testPort; myp4.Client = _client1; myp4.User = _user1; myp4.Connect(); P4RecordSet info = myp4.Run("info"); //myp4.Disconnect(); } // prior to a fix, nUnit would hang if you didn't disconnect() [Test] public void Test064_NoDisconnect() { P4Connection myp4 = new P4Connection(); myp4.Port = _testPort; myp4.Client = _client1; myp4.User = _user1; myp4.Connect(); P4Form job = myp4.Fetch_Form("job"); //myp4.Disconnect(); } */ #endregion [Test] [ExpectedException(typeof(P4API.Exceptions.FormFetchException))] public void Test065_BadFormCommand() { // try to fetch a form with a real command, but not a form P4Form bogus = p4.Fetch_Form("changes", "-m5", "//..."); } [Test] [ExpectedException(typeof(P4API.Exceptions.FormFetchException))] public void Test066_BadFormCommand() { // try to fetch a form with a real command, but not a form // this time there's only 1 record, but wont have a specdef P4Form bogus = p4.Fetch_Form("changes", "-m1", "//..."); } [Test] public void Test067_SaveChangeWithU() { // fetch a submitted changelist P4Form chg = p4.Fetch_Form("change", "1"); // -u flag available 2007.2 and newer if (p4.ServerLevel >= 23) { chg["Description"] = "Changed with -u"; p4.Save_Form(chg, "-u"); chg = p4.Fetch_Form("change", "1"); Assert.AreEqual("Changed with -u\n", chg["Description"]); } // check -f still works chg["Description"] = "Changed with -f"; p4.Save_Form(chg, true); chg = p4.Fetch_Form("change", "1"); Assert.AreEqual("Changed with -f\n", chg["Description"]); } [Test] public void Test068_MergeTest() { // setup a merge scenario string testPath = Path.Combine(p4ClientRootDirectory, "test068"); //Create some test files Directory.CreateDirectory(testPath); P4PendingChangelist cl = p4.CreatePendingChangelist("Test068a"); string[] args = new string[12]; args[0] = "-c"; args[1] = cl.Number.ToString(); // Write out base file string fn = Path.Combine(testPath, "mergeme.txt"); StreamWriter sw = File.CreateText(fn); sw.WriteLine("line 1"); sw.WriteLine("line 2"); sw.WriteLine("line 3"); sw.Close(); P4UnParsedRecordSet r = p4.RunUnParsed("add", "-c", cl.Number.ToString(), fn); r.Dump(); r = cl.Submit(); r.Dump(); Assert.AreEqual("Submitting change ", r.Messages[0].Substring(0,18), "Unexpected output from p4 submit"); // Make 'thier' file cl = p4.CreatePendingChangelist("Test068b"); r = p4.RunUnParsed("edit", "-c", cl.Number.ToString(), fn); sw = File.CreateText(fn); sw.WriteLine("line 1"); sw.WriteLine("line 2 b"); sw.WriteLine("line 3"); sw.Close(); r = cl.Submit(); r.Dump(); Assert.AreEqual("Submitting change ", r.Messages[0].Substring(0, 18), "Unexpected output from p4 submit"); // Make 'your' file r = p4.RunUnParsed("sync", fn + "#1"); r.Dump(); cl = p4.CreatePendingChangelist("Test068c"); r = p4.RunUnParsed("edit", "-c", cl.Number.ToString(), fn); sw = File.CreateText(fn); sw.WriteLine("line 1"); sw.WriteLine("line 2"); sw.WriteLine("line 3 c"); sw.Close(); r = p4.RunUnParsed("sync", fn); r.Dump(); // finally now we can resolve // Just quit. Make sure the submit fails mergeCallback mc = new mergeCallback(MergeAction.Quit); p4.RunCallback(mc, "resolve", fn); r = cl.Submit(); r.Dump(); // Should have an error (files need to be resolved); Assert.AreEqual(822418474, r.P4Messages[2].Identity); // now do a skip. Submit should fail again mc = new mergeCallback(MergeAction.Skip); p4.RunCallback(mc, "resolve", fn); r = cl.Submit(); r.Dump(); // Should have an error (files need to be resolved); Assert.AreEqual(822418474, r.P4Messages[2].Identity); // now do an accept thiers. Verify by doing a diff } [Test] public void Test069_RecordsetCallback() { //test that a user can use the callback themselves to replace code using the Run method P4RecordSet r1 = p4.Run("info"); P4RecordsetCallback rcb = new P4RecordsetCallback(); p4.RunCallback(rcb, "info"); P4RecordSet r2 = rcb.Recordset; Assert.AreEqual(r1.Records.Length, r2.Records.Length); } [Test] public void Test070_BugPasswordPersistience() { using (P4Connection myp4 = new P4Connection()) { myp4.User = "TestUser2"; myp4.Port = _testPort; myp4.Client = _client1; myp4.Password = ""; myp4.Connect(); Console.WriteLine(myp4.Password); //P4RecordSet r1; PasswordSetter setter = new PasswordSetter(myp4); setter.SetPassword("", "testPass"); Console.WriteLine(myp4.Password); //r1 = myp4.Run("login", "-s"); //Console.WriteLine(r1.Messages[0]); Console.WriteLine(myp4.Password); } //test that a user can use the callback themselves to replace code using the Run method //r1 = myp4.Run("logout", "-a"); //myp4.TicketFile = "bogus"; //Console.WriteLine(r1.Messages[0]); //myp4.Password = "password"; //myp4.Login("badpass"); using (P4Connection myp4 = new P4Connection()) { myp4.User = "TestUser2"; myp4.Port = _testPort; myp4.Client = _client1; myp4.Password = "testPass"; myp4.Connect(); //P4RecordSet r1; //r1 = myp4.Run("login", "-s"); //Console.WriteLine(r1.Messages[0]); Console.WriteLine(myp4.Password); P4Form form = myp4.Fetch_Form("client"); Assert.AreEqual("TestClient1", form["Client"]); } // Bug... the Password did not persist across disconnect-reconnect sessions. //myp4.Disconnect(); //using (P4Connection myp4 = new P4Connection()) //{ // myp4.Connect(); // //myp4.Password = "password"; // P4Form form = myp4.Fetch_Form("client"); // //P4UnParsedRecordSet rs = p4.Save_Form(form); // Assert.AreEqual("TestClient1", form["Client"]); //} } [Test] public void Test101_CancelCallback() { cancelCallback callback = new cancelCallback(); p4.RunCallback(callback, "sync", "-f", "//..."); Assert.IsTrue(callback.WasCanceled); callback.WasCanceled = false; p4.RunCallback(callback, "sync", "-f", "//..."); Assert.IsTrue(callback.WasCanceled); } [Test] public void Test100_LoadTesting_LookForMemoryLeaks() { bool run = false; //uncomment to actually do this... it slows the test down a bit //run = true; if (run) { // fetch the latest changelist P4RecordSet rs = p4.Run("changes", "-ssubmitted", "-m1"); int beginFolder = int.Parse(rs[0]["change"]) + 1; //branch 1000 files, 1 changelist/p4connection at a time for (int i = beginFolder; i < 1000 + beginFolder; i++) { integTest(i); } } } private void integTest(int folderNumber) { P4Connection p4Con = new P4Connection(); p4Con.Port = _testPort; p4Con.CallingProgram = "P4.Net Test Harness"; p4Con.CallingVersion = "1.0"; p4Con.Client = _client1; p4Con.User = _user1; p4Con.Connect(); string sourcePath = "//depot/test003/File0"; string destPath = string.Format("//depot/test100/{0}/File0", folderNumber); P4PendingChangelist cl = p4Con.CreatePendingChangelist(string.Format("integ {0}", folderNumber)); P4RecordSet IntegResult = p4Con.Run("integ", "-c", cl.Number.ToString(), sourcePath, destPath); P4UnParsedRecordSet CLResult = cl.Submit(); string[] DesiredResult = { string.Format("Submitting change {0}.", folderNumber), "Locking 1 files ..." , string.Format("branch //depot/test100/{0}/File0#1", folderNumber), string.Format("Change {0} submitted.", folderNumber)}; Assert.AreEqual(DesiredResult, CLResult.Messages); p4Con.Disconnect(); } [Test] public void Test200_ConnectionProperties() { p4.Host = "host"; //p4.CallingProgram = "P4.NetTestHarness"; Assert.AreEqual(true, p4.IsValidConnection(true, true)); p4.Client = "bogus-client"; string dir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase); p4.CWD = dir; Assert.AreEqual("host", p4.Host); Assert.AreEqual("bogus-client", p4.Client); Assert.AreEqual(dir, p4.CWD); Assert.AreEqual(_testPort, p4.Port); Assert.AreEqual("P4.Net Test Harness", p4.CallingProgram); Assert.AreEqual("1.0", p4.CallingVersion); Assert.AreEqual(false, p4.IsValidConnection(true, true)); } [Test] [ExpectedException(typeof(P4API.Exceptions.PerforceInitializationError))] public void Test201_BogusConnection() { P4Connection bogus = new P4Connection(); bogus.Port = "1234"; bogus.Connect(); } [Test] public void Test888_CleanUpFileSystem() { // Remove all Read-Only attitude RemoveReadOnly(p4ClientRootDirectory); Directory.Delete(p4ClientRootDirectory, true); RemoveReadOnly(p4ClientRootDirectory2); Directory.Delete(p4ClientRootDirectory2, true); } [Test] public void Test999_Disconnect() { //duh p4.Disconnect(); Trace.Flush(); Trace.Listeners.Remove(consoleListner); consoleListner.Close(); } private void OnPrompt(object sender, P4PromptEventArgs e) { switch (e.Message) { case ("Enter new password: "): e.Response = "password"; break; case ("Re-enter new password: "): e.Response = "password"; break; } } private void OnResolvePromptMerge(object sender, P4PromptEventArgs e) { // return m, to try and manually resolve it onResolveCount++; if (onResolveCount < 10) { e.Response = "m"; } else { e.Response = "s"; } } private int onResolveRunMergeToolCount; private void OnResolveRunMergeTool(object sender, P4PromptEventArgs e) { Console.WriteLine("OnResolve"); Console.WriteLine(e.Message); // first promt we run the merge tool. After that we // accept the merged version switch (onResolveRunMergeToolCount) { case 0: e.Response = "m"; break; case 1: e.Response = "a"; break; default: e.Response = "s"; break; } onResolveRunMergeToolCount++; } private static void OnPromptPause(object sender, P4PromptEventArgs e) { Console.WriteLine("On Prompt..."); System.Threading.Thread.Sleep(11000); mre.Set(); System.Threading.Thread.Sleep(500); e.Response = "password"; Console.WriteLine("Exiting On Prompt..."); } //private static void RunOnNewThread() //{ // P4Connection p4 = new P4Connection(); // p4.Port = this._testPort ; // p4.User = _user1; // p4.Connect(); // p4.OnPrompt += new OnPromptEventHandler(OnPromptPause); // try // { // Console.WriteLine("Running login"); // p4.RunUnParsed("login"); // Console.WriteLine("after login"); // // should have been killed in the other connection // Console.WriteLine("testing connection"); // P4UnParsedRecordSet r = p4.RunUnParsed("info"); // Console.WriteLine(r.Messages[0]); // /*if (!p4.IsValidConnection(true, false)) // { // Console.WriteLine("connection failed"); // Assert.Fail("Did not re-establish dropped connection."); // } // */ // } // catch (Exception e) // { // // not to worry here... we didn't supply a valid password // //Console.WriteLine(e.Result.ErrorMessage); // Console.WriteLine(e.StackTrace); // } // finally // { // Console.WriteLine("dude"); // p4.Disconnect(); // } // mre2.Set(); //} private void RemoveReadOnly(string path) { try { DirectoryInfo current = new DirectoryInfo(path); current.Attributes = FileAttributes.Normal; foreach (FileSystemInfo file in current.GetFileSystemInfos()) file.Attributes = FileAttributes.Normal; foreach (DirectoryInfo folder in current.GetDirectories()) RemoveReadOnly(folder.FullName); } catch (System.Exception excpt) { Console.WriteLine(excpt.Message); } } } class PasswordSetter { private P4Connection _p4 = null; private string _oldPassword = ""; private string _newPassword = ""; public PasswordSetter(P4Connection p4) { _p4 = p4; } public void SetPassword(string OldPassword, string NewPassword) { OnPromptEventHandler eh = new OnPromptEventHandler(OnPrompt); _p4.OnPrompt += eh; _oldPassword = OldPassword; _newPassword = NewPassword; //run passwd P4UnParsedRecordSet r = _p4.RunUnParsed("passwd"); //Clear the event just in case _p4.OnPrompt -= eh; //Clear the passwords from memory _newPassword = ""; _oldPassword = ""; } private void OnPrompt(object sender, P4PromptEventArgs e) { switch (e.Message) { case ("Enter old password: "): e.Response = _oldPassword; break; case ("Enter new password: "): e.Response = _newPassword; break; case ("Re-enter new password: "): e.Response = _newPassword; break; } } } public class PrintHelper { private P4Connection _p4 = null; private MemoryStream _ms = null; private StreamReader _sr = null; private string _s = null; public PrintHelper(P4Connection p4) { _p4 = p4; } public string PrintTextFile(string depotpath) { OnPrintStreamEventHandler eh = new OnPrintStreamEventHandler(OnPrint); OnPrintEndEventHandler eh2 = new OnPrintEndEventHandler(OnPrintEnd); _p4.OnPrintStream += eh; _p4.OnPrintEndFile += eh2; _p4.PrintStreamEvents(depotpath); _p4.OnPrintStream -= eh; _p4.OnPrintEndFile -= eh2; return _s; } private void OnPrintEnd(P4PrintStreamEventArgs e, Stream s) { _ms.Position = 0; _s = _sr.ReadToEnd(); _sr.Close(); s.Close(); _ms = null; _sr = null; } private void OnPrint(P4PrintStreamEventArgs e, out Stream s) { _ms = new MemoryStream(); _sr = new StreamReader(_ms); s = _ms; } } internal class mergeCallback : P4Callback { MergeAction _action; public mergeCallback(MergeAction action) { _action = action; } public override void OutputRecord(P4Record record) { //throw new NotImplementedException(); Console.WriteLine("OutputRecord"); } public override void OutputMessage(P4Message message) { message.Dump(); } public override MergeAction ResolveFile(MergeData mergeData) { Console.WriteLine("MergeData::BaseFile {0}", mergeData.BaseFile); Console.WriteLine("MergeData::TheirFile {0}", mergeData.TheirFile); Console.WriteLine("MergeData::YourFile {0}", mergeData.YourFile); Console.WriteLine("MergeData::ResultFile {0}", mergeData.ResultFile); Console.WriteLine("MergeData::BaseName {0}", mergeData.BaseName); Console.WriteLine("MergeData::TheirName {0}", mergeData.TheirName); Console.WriteLine("MergeData::YourName {0}", mergeData.YourName); Console.WriteLine("MergeData::MergeHint {0}", mergeData.MergeHint.ToString()); // mergeData.RunMergeTool(); return _action; } } internal class cancelCallback : P4Callback { public int FilesSynced = 0; public bool WasCanceled = false; #region P4Callback Members public override bool Cancel() { //Trace.WriteLine("cancelCallback.Cancel called."); if (FilesSynced > 1) { WasCanceled = true; return true; } return false; } public override void OutputRecord(P4Record record) { // sleep for 1 second to see if we can get the callback to call. //Trace.WriteLine("OutputRecord."); Thread.Sleep(300); FilesSynced++; } public override void OutputMessage(P4Message message) { //Trace.WriteLine("OutputMessage: " + message.Format()); } #endregion } }