Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,3 @@
{
"createSeparatePackage": false
}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b8e4d0db015969e4b807acc03df70d15
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0f6c76b7677c532458e1a8efec3b2c76
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,594 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models;
using Unity.Cloud.Collaborate.Models.Structures;
namespace Unity.Cloud.Collaborate.Tests.Models
{
public class ChangesModelTests
{
class TestableChangesModel : ChangesModel
{
public TestSourceControlProvider Provider => (TestSourceControlProvider)m_Provider;
public TestableChangesModel() : base (new TestSourceControlProvider())
{
}
public void SetToggled([CanBeNull] Dictionary<string, bool> toggled = null)
{
if (toggled != null)
{
toggledEntries = toggled;
}
}
internal override void UpdateChangeList(IReadOnlyList<IChangeEntry> list)
{
base.UpdateChangeList(list);
ValidateData();
}
public override bool UpdateEntryToggle(string path, bool value)
{
var refresh = base.UpdateEntryToggle(path, value);
ValidateData();
return refresh;
}
void ValidateData()
{
var toggledCount = 0;
foreach (var x in entryData.Select(entry => entry.Value))
{
Assert.IsTrue(toggledEntries.TryGetValue(x.Entry.Path, out var toggled) && x.Toggled == toggled);
if (!x.All && toggled) toggledCount++;
}
Assert.AreEqual(toggledCount, ToggledCount);
}
}
[Test]
public void ChangesModel_NullSourceControlEntries_EmptyResultLists()
{
var model = new TestableChangesModel();
model.OnStart();
model.UpdateChangeList(new List<IChangeEntry>());
var fullList = model.GetAllEntries();
Assert.AreEqual(1, fullList.Count);
Assert.IsTrue(fullList[0].All);
Assert.AreEqual(0, model.GetToggledEntries().Count);
Assert.AreEqual(0, model.GetUntoggledEntries().Count);
Assert.AreEqual(0, model.ToggledCount);
}
[Test]
public void ChangesModel_EmptySourceControlEntries_EmptyResultLists()
{
var model = new TestableChangesModel();
model.OnStart();
model.UpdateChangeList(new List<IChangeEntry>());
var fullList = model.GetAllEntries();
Assert.AreEqual(1, fullList.Count);
Assert.IsTrue(fullList[0].All);
Assert.AreEqual(0, model.GetToggledEntries().Count);
Assert.AreEqual(0, model.GetUntoggledEntries().Count);
Assert.AreEqual(0, model.ToggledCount);
}
[Test]
public void ChangesModel_SingleSourceControlEntries_SingleUntoggledResult()
{
var model = new TestableChangesModel();
model.OnStart();
var changes = BuildChangesList(1);
model.UpdateChangeList(changes);
var fullList = model.GetAllEntries();
Assert.AreEqual(2, fullList.Count);
Assert.IsTrue(fullList[0].All);
Assert.IsFalse(fullList[0].Toggled);
Assert.IsFalse(fullList[1].All);
Assert.IsFalse(fullList[1].Toggled);
var toggledList = model.GetToggledEntries();
Assert.AreEqual(0, toggledList.Count);
var untoggledList = model.GetUntoggledEntries();
Assert.AreEqual(1, untoggledList.Count);
Assert.IsFalse(untoggledList[0].All);
Assert.IsFalse(untoggledList[0].Toggled);
Assert.AreEqual(0, model.ToggledCount);
}
[Test]
public void ChangesModel_MultipleSourceControlEntries_ToggleSingle()
{
const int entryCount = 5;
var model = new TestableChangesModel();
model.OnStart();
var changes = BuildChangesList(entryCount);
model.UpdateChangeList(changes);
var fullList = model.GetAllEntries();
Assert.AreEqual(entryCount, model.TotalCount);
Assert.AreEqual(entryCount + 1, fullList.Count);
Assert.IsTrue(fullList[0].All);
var toggledEntry = fullList[entryCount / 2 + 1];
model.UpdateEntryToggle(toggledEntry.Entry.Path, true);
Assert.IsTrue(toggledEntry.Toggled);
fullList = model.GetAllEntries();
Assert.AreEqual(entryCount + 1, fullList.Count);
foreach (var entry in fullList)
{
if (entry == fullList[0])
{
Assert.IsTrue(entry.All);
}
else
{
Assert.IsFalse(entry.All);
}
if (entry == toggledEntry)
{
Assert.IsTrue(entry.Toggled);
}
else
{
Assert.IsFalse(entry.Toggled);
}
}
var toggledList = model.GetToggledEntries();
Assert.AreEqual(1, toggledList.Count);
Assert.AreEqual(toggledEntry, toggledList[0]);
var untoggledList = model.GetUntoggledEntries();
Assert.AreEqual(entryCount -1, untoggledList.Count);
foreach (var entry in untoggledList)
{
Assert.IsFalse(entry.All);
Assert.AreNotEqual(toggledEntry, entry);
}
Assert.AreEqual(1, model.ToggledCount);
}
[Test]
public void ChangesModel_MultipleSourceControlEntries_ToggleAll()
{
const int entryCount = 5;
var model = new TestableChangesModel();
model.OnStart();
var changes = BuildChangesList(entryCount);
model.UpdateChangeList(changes);
var fullList = model.GetAllEntries();
Assert.AreEqual(entryCount + 1, fullList.Count);
Assert.IsTrue(fullList[0].All);
model.UpdateEntryToggle(fullList[0].Entry.Path, true);
fullList = model.GetAllEntries();
Assert.AreEqual(entryCount + 1, fullList.Count);
foreach (var entry in fullList)
{
if (entry == fullList[0])
{
Assert.IsTrue(entry.All);
}
else
{
Assert.IsFalse(entry.All);
}
Assert.IsTrue(entry.Toggled);
}
var toggledList = model.GetToggledEntries();
Assert.AreEqual(entryCount, toggledList.Count);
foreach (var entry in toggledList)
{
Assert.IsFalse(entry.All);
}
var untoggledList = model.GetUntoggledEntries();
Assert.AreEqual(0, untoggledList.Count);
Assert.AreEqual(entryCount, model.ToggledCount);
}
[Test]
public void ChangesModel_MultipleSourceControlEntries_ToggleAllIndividually()
{
const int entryCount = 5;
var model = new TestableChangesModel();
model.OnStart();
var changes = BuildChangesList(entryCount);
model.UpdateChangeList(changes);
var fullList = model.GetAllEntries();
Assert.AreEqual(entryCount + 1, fullList.Count);
Assert.IsTrue(fullList[0].All);
fullList = model.GetAllEntries();
foreach (var entry in fullList.Where(entry => !entry.All))
{
model.UpdateEntryToggle(entry.Entry.Path, true);
}
Assert.AreEqual(entryCount + 1, fullList.Count);
foreach (var entry in fullList)
{
if (entry == fullList[0])
{
Assert.IsTrue(entry.All);
}
else
{
Assert.IsFalse(entry.All);
}
Assert.IsTrue(entry.Toggled);
}
var toggledList = model.GetToggledEntries();
Assert.AreEqual(entryCount, toggledList.Count);
foreach (var entry in toggledList)
{
Assert.IsFalse(entry.All);
}
var untoggledList = model.GetUntoggledEntries();
Assert.AreEqual(0, untoggledList.Count);
Assert.AreEqual(entryCount, model.ToggledCount);
}
[Test]
public void ChangesModel_MultipleSourceControlEntries_UntoggleSingleFromAll()
{
const int entryCount = 5;
var model = new TestableChangesModel();
model.OnStart();
var changes = BuildChangesList(entryCount);
model.UpdateChangeList(changes);
var fullList = model.GetAllEntries();
Assert.AreEqual(entryCount + 1, fullList.Count);
Assert.IsTrue(fullList[0].All);
model.UpdateEntryToggle(fullList[0].Entry.Path, true);
var untoggledEntry = fullList[entryCount / 2 + 1];
model.UpdateEntryToggle(untoggledEntry.Entry.Path, false);
Assert.IsFalse(untoggledEntry.Toggled);
fullList = model.GetAllEntries();
Assert.AreEqual(entryCount + 1, fullList.Count);
foreach (var entry in fullList)
{
if (entry == fullList[0])
{
Assert.IsTrue(entry.All);
}
else
{
Assert.IsFalse(entry.All);
}
if (entry == untoggledEntry || entry.All)
{
Assert.IsFalse(entry.Toggled);
}
else
{
Assert.IsTrue(entry.Toggled);
}
}
var toggledList = model.GetToggledEntries();
Assert.AreEqual(entryCount - 1, toggledList.Count);
foreach (var entry in toggledList)
{
Assert.IsFalse(entry.All);
Assert.AreNotEqual(untoggledEntry, entry);
}
var untoggledList = model.GetUntoggledEntries();
Assert.AreEqual(1, untoggledList.Count);
Assert.AreEqual(untoggledEntry, untoggledList[0]);
Assert.AreEqual(entryCount - 1, model.ToggledCount);
}
[Test]
public void ChangesModel_MultipleSourceControlEntries_SomeConflicted()
{
const string conflictedPrefix = "conflicted-path";
var model = new TestableChangesModel();
model.OnStart();
var changes = new List<IChangeEntry>();
AddEntry(changes, "path1", ChangeEntryStatus.Modified, false);
AddEntry(changes, "path2", ChangeEntryStatus.Modified, false);
AddEntry(changes, "path3", ChangeEntryStatus.Modified, false);
AddEntry(changes, $"{conflictedPrefix}4", ChangeEntryStatus.Modified, false, true);
AddEntry(changes, $"{conflictedPrefix}5", ChangeEntryStatus.Modified, false, true);
model.UpdateChangeList(changes);
var conflictedList = model.GetConflictedEntries();
model.Provider.ConflictedState = true;
Assert.IsTrue(model.Conflicted);
Assert.AreEqual(2, model.ConflictedCount);
Assert.AreEqual(2, conflictedList.Count);
Assert.IsFalse(conflictedList[0].All);
Assert.IsFalse(conflictedList[1].All);
Assert.IsTrue(conflictedList[0].Conflicted);
Assert.IsTrue(conflictedList[1].Conflicted);
Assert.IsTrue(conflictedList[0].Entry.Path.StartsWith(conflictedPrefix));
Assert.IsTrue(conflictedList[1].Entry.Path.StartsWith(conflictedPrefix));
}
[Test]
public void ChangesModel_InitializeFromDictionary_TransfersToggledFlag()
{
const int entryCount = 5;
const int toggledCount = 2;
const int toggledIndex1 = 0;
const int toggledIndex2 = entryCount / 2 + 1;
const int untoggledIndex = entryCount - 1;
var changes = BuildChangesList(entryCount);
var dictionary = new Dictionary<string, bool>();
changes.ForEach( (x) => dictionary[x.Path] = false );
dictionary[changes[toggledIndex1].Path] = true;
dictionary[changes[toggledIndex2].Path] = true;
dictionary[changes[untoggledIndex].Path] = false;
var model = new TestableChangesModel();
model.OnStart();
model.SetToggled(dictionary);
model.UpdateChangeList(changes);
var fullList = model.GetAllEntries();
Assert.AreEqual(entryCount + 1, fullList.Count);
foreach (var entry in fullList)
{
if (entry == fullList[0])
{
Assert.IsTrue(entry.All);
}
else
{
Assert.IsFalse(entry.All);
}
if (entry.Entry.Path == changes[toggledIndex1].Path || entry.Entry.Path == changes[toggledIndex2].Path)
{
Assert.IsTrue(entry.Toggled);
}
else
{
Assert.IsFalse(entry.Toggled);
}
}
var toggledList = model.GetToggledEntries();
Assert.AreEqual(toggledCount, toggledList.Count);
foreach (var entry in toggledList)
{
Assert.IsTrue(entry.Entry.Path == changes[toggledIndex1].Path || entry.Entry.Path == changes[toggledIndex2].Path);
Assert.IsFalse(entry.All);
Assert.IsTrue(entry.Toggled);
}
var untoggledList = model.GetUntoggledEntries();
Assert.AreEqual(entryCount - toggledCount, untoggledList.Count);
foreach (var entry in untoggledList)
{
Assert.IsTrue(entry.Entry.Path != changes[toggledIndex1].Path && entry.Entry.Path != changes[toggledIndex2].Path);
Assert.IsFalse(entry.All);
Assert.IsFalse(entry.Toggled);
}
}
[Test]
public void ChangesModel_SearchFilters_CaseInsensitive()
{
var changes = new List<IChangeEntry>();
AddEntry(changes, "alpha1", ChangeEntryStatus.Modified, false);
AddEntry(changes, "alpha2", ChangeEntryStatus.Modified, false);
AddEntry(changes, "bravo", ChangeEntryStatus.Modified, false);
AddEntry(changes, "charlie", ChangeEntryStatus.Modified, false);
AddEntry(changes, "Delta3", ChangeEntryStatus.Modified, false);
AddEntry(changes, "delta4", ChangeEntryStatus.Modified, false);
AddEntry(changes, "delta5", ChangeEntryStatus.Modified, false);
AddEntry(changes, "echo", ChangeEntryStatus.Modified, false);
AddEntry(changes, "Foxtrot6", ChangeEntryStatus.Modified, false);
AddEntry(changes, "Foxtrot7", ChangeEntryStatus.Modified, false);
AddEntry(changes, "golf", ChangeEntryStatus.Modified, false);
var dictionary = new Dictionary<string, bool>
{
["delta5"] = true, ["Foxtrot6"] = true, ["Foxtrot7"] = true, ["golf"] = true
};
var model = new TestableChangesModel();
model.OnStart();
model.SetToggled(dictionary);
model.UpdateChangeList(changes);
var fullList = model.GetAllEntries();
Assert.AreEqual(changes.Count, model.TotalCount);
Assert.AreEqual(changes.Count + 1, fullList.Count);
Assert.IsTrue(fullList[0].All);
var searchFullList = model.GetAllEntries("alpha");
Assert.AreEqual(2, searchFullList.Count);
foreach (var entry in searchFullList)
{
Assert.IsFalse(entry.All);
Assert.IsFalse(entry.Toggled);
}
var toggledList = model.GetToggledEntries();
Assert.AreEqual(dictionary.Count, toggledList.Count);
foreach (var entry in toggledList)
{
Assert.IsFalse(entry.All);
}
var searchToggledList = model.GetToggledEntries("fox");
Assert.AreEqual(2, searchToggledList.Count);
foreach (var entry in searchToggledList)
{
Assert.IsTrue(entry.Entry.Path.ToLower().Contains("fox"));
Assert.IsFalse(entry.All);
Assert.IsTrue(entry.Toggled);
}
var untoggledList = model.GetUntoggledEntries();
Assert.AreEqual(changes.Count - dictionary.Count, untoggledList.Count);
var searchUntoggledList = model.GetUntoggledEntries("Del");
Assert.AreEqual(2, searchUntoggledList.Count);
foreach (var entry in searchUntoggledList)
{
Assert.IsTrue(entry.Entry.Path.ToLower().Contains("del"));
Assert.AreNotEqual("delta5", entry.Entry.Path);
Assert.IsFalse(entry.All);
Assert.IsFalse(entry.Toggled);
}
Assert.AreEqual(dictionary.Count, model.ToggledCount);
}
[Test]
public void TestRequestInitialData()
{
var provider = new TestSourceControlProvider();
var model = new ChangesModel(provider);
model.OnStart();
var callCount = 0;
bool? callValue = null;
model.BusyStatusUpdated += b =>
{
callCount++;
callValue = b;
};
Assert.IsFalse(model.Busy);
model.RequestInitialData();
Assert.AreEqual(1, provider.RequestedChangeListCount);
Assert.IsNotNull(provider.RequestedChangeListCallback);
Assert.IsTrue(model.Busy);
Assert.IsTrue(callValue);
provider.RequestedChangeListCallback.Invoke(new List<IChangeEntry>());
Assert.IsFalse(model.Busy);
Assert.IsFalse(callValue);
Assert.AreEqual(2, callCount);
}
[Test]
public void TestReceiveUpdatedChangeListEvent()
{
var provider = new TestSourceControlProvider();
var model = new ChangesModel(provider);
model.OnStart();
var callCount = 0;
bool? callValue = null;
model.BusyStatusUpdated += b =>
{
callCount++;
callValue = b;
};
Assert.IsFalse(model.Busy);
provider.TriggerUpdatedChangeEntries();
Assert.AreEqual(1, provider.RequestedChangeListCount);
Assert.IsNotNull(provider.RequestedChangeListCallback);
Assert.IsTrue(model.Busy);
Assert.IsTrue(callValue);
provider.RequestedChangeListCallback.Invoke(new List<IChangeEntry>());
Assert.IsFalse(model.Busy);
Assert.IsFalse(callValue);
Assert.AreEqual(2, callCount);
}
[Test]
public void TestRequestDiff()
{
var provider = new TestSourceControlProvider();
var model = new ChangesModel(provider);
model.OnStart();
const string path = "path";
model.RequestDiffChanges(path);
Assert.AreEqual(1, provider.RequestedDiffChangesCount);
Assert.AreEqual(path, provider.RequestedDiffChangesPath);
}
[Test]
public void TestRequestDiscard()
{
var provider = new TestSourceControlProvider();
var model = new ChangesModel(provider);
model.OnStart();
const string path = "path";
var entry = new ChangeEntry(path);
model.RequestDiscard(entry);
Assert.AreEqual(1, provider.RequestedDiscardCount);
Assert.AreEqual(path, provider.RequestedDiscardEntry?.Path);
}
[Test]
public void TestRequestPublish()
{
var provider = new TestSourceControlProvider();
var model = new ChangesModel(provider);
model.OnStart();
const string message = "message";
model.RequestPublish(message, new List<IChangeEntry> { new ChangeEntry("path1"), new ChangeEntry("path2")});
Assert.AreEqual(1, provider.RequestedPublishCount);
Assert.AreEqual(message, provider.RequestedPublishMessage);
Assert.AreEqual(2, provider.RequestedPublishList?.Count);
}
static void AddEntry(ICollection<IChangeEntry> list, string pathTag, ChangeEntryStatus status, bool staged, bool unmerged = false)
{
list.Add(new ChangeEntry(pathTag, $"Original{pathTag}", status, staged, unmerged));
}
static List<IChangeEntry> BuildChangesList(int count)
{
var changes = new List<IChangeEntry>();
for (var i = 0; i < count; i++)
{
AddEntry(changes, $"Path{i}", ChangeEntryStatus.Modified, false);
}
return changes;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ac075bf7cbc97f4fbba27c78feb9c18
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,130 @@
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models;
namespace Unity.Cloud.Collaborate.Tests.Models
{
public class HistoryModelTests
{
TestSourceControlProvider m_Provider;
HistoryModel m_Model;
int m_BusyStatusUpdatedCount;
int m_EntryCountUpdatedCount;
int m_HistoryListReceivedCount;
int m_HistoryListUpdatedCount;
int m_SelectedRevisionReceivedCount;
[SetUp]
public void Setup()
{
m_Provider = new TestSourceControlProvider();
m_Model = new HistoryModel(m_Provider);
m_Model.OnStart();
m_BusyStatusUpdatedCount = 0;
m_EntryCountUpdatedCount = 0;
m_HistoryListReceivedCount = 0;
m_HistoryListUpdatedCount = 0;
m_SelectedRevisionReceivedCount = 0;
m_Model.BusyStatusUpdated += _ => m_BusyStatusUpdatedCount++;
m_Model.EntryCountUpdated += _ => m_EntryCountUpdatedCount++;
m_Model.HistoryListReceived += _ => m_HistoryListReceivedCount++;
m_Model.HistoryListUpdated += () => m_HistoryListUpdatedCount++;
m_Model.SelectedRevisionReceived += _ => m_SelectedRevisionReceivedCount++;
}
[TearDown]
public void TearDown()
{
m_Model = null;
m_Provider = null;
}
[Test]
public void TestHistoryListUpdated()
{
m_Provider.TriggerUpdatedHistoryEntries();
Assert.AreEqual(1, m_HistoryListUpdatedCount);
}
[Test]
public void TestIsBusyAndEntryCount()
{
m_Model.RequestEntryNumber();
Assert.AreEqual(1, m_Provider.RequestedHistoryCountCount);
Assert.AreEqual(false, m_Model.Busy);
Assert.AreEqual(2, m_BusyStatusUpdatedCount);
Assert.AreEqual(1, m_EntryCountUpdatedCount);
}
[Test]
public void TestRequestingPageOfRevisions()
{
m_Model.PageNumber = 2;
m_Model.RequestPageOfRevisions(10);
Assert.AreEqual(1, m_Provider.RequestedHistoryListCount);
Assert.AreEqual(20, m_Provider.RequestedHistoryListOffset);
Assert.AreEqual(10, m_Provider.RequestedHistoryListSize);
Assert.AreEqual(2, m_BusyStatusUpdatedCount);
Assert.AreEqual(1, m_HistoryListReceivedCount);
}
[Test]
public void TestRequestingSingleRevision()
{
const string revisionId = "123";
Assert.AreEqual(false, m_Model.IsRevisionSelected);
Assert.AreEqual(string.Empty, m_Model.SelectedRevisionId);
m_Model.RequestSingleRevision(revisionId);
Assert.AreEqual(true, m_Model.IsRevisionSelected);
Assert.AreEqual(1, m_Provider.RequestedHistoryRevisionCount);
Assert.AreEqual(revisionId, m_Provider.RequestedHistoryRevisionId);
Assert.AreEqual(2, m_BusyStatusUpdatedCount);
Assert.AreEqual(1, m_SelectedRevisionReceivedCount);
}
[Test]
public void TestRequestUpdateTo()
{
const string revisionId = "123";
m_Model.RequestUpdateTo(revisionId);
Assert.AreEqual(1, m_Provider.RequestedUpdateToCount);
Assert.AreEqual(revisionId, m_Provider.RequestedUpdateToRevisionId);
}
[Test]
public void TestRequestRestoreTo()
{
const string revisionId = "123";
m_Model.RequestRestoreTo(revisionId);
Assert.AreEqual(1, m_Provider.RequestedRestoreToCount);
Assert.AreEqual(revisionId, m_Provider.RequestedRestoreToRevisionId);
}
[Test]
public void TestRequestGoBackTo()
{
const string revisionId = "123";
m_Model.RequestGoBackTo(revisionId);
Assert.AreEqual(1, m_Provider.RequestedGoBackToCount);
Assert.AreEqual(revisionId, m_Provider.RequestedGoBackToRevisionId);
}
[Test]
public void TestRevert()
{
const string revisionId = "123";
m_Model.RequestRevert(revisionId, new List<string> { "a", "b", "c" });
Assert.AreEqual(1, m_Provider.RequestedRevertCount);
Assert.AreEqual(revisionId, m_Provider.RequestedRevertRevisionId);
Assert.AreEqual(3, m_Provider.RequestedRevertFileCount);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2079ae55f950aa4439a7ca7af8a9c136
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2fd9db3c67f54e59bb315a02250dbaf3
timeCreated: 1576179242

View file

@ -0,0 +1,254 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models.Api;
using Unity.Cloud.Collaborate.Models.Enums;
using Unity.Cloud.Collaborate.Models.Structures;
using UnityEditor;
using UnityEngine;
namespace Unity.Cloud.Collaborate.Models.Providers
{
[UsedImplicitly]
internal class MockSourceControlProvider : ISourceControlProvider
{
public event Action UpdatedChangeList = delegate { };
public event Action<IReadOnlyList<string>> UpdatedSelectedChangeList = delegate { };
public event Action UpdatedHistoryEntries = delegate { };
public event Action<bool> UpdatedConflictState = delegate { };
public event Action<bool> UpdatedRemoteRevisionsAvailability = delegate { };
public event Action<ProjectStatus> UpdatedProjectStatus = delegate { };
public event Action<bool> UpdatedOperationStatus = delegate { };
public event Action<IProgressInfo> UpdatedOperationProgress = delegate { };
public event Action<IErrorInfo> ErrorOccurred = delegate { };
public event Action ErrorCleared = delegate { };
List<IChangeEntry> m_Changes;
readonly List<IHistoryEntry> m_History;
public MockSourceControlProvider()
{
m_Changes = new List<IChangeEntry>
{
new ChangeEntry("SomePath", "SomeOriginalPath", ChangeEntryStatus.Modified),
new ChangeEntry("SomeConflictedPath2", "SomeOriginalPath", ChangeEntryStatus.Modified, unmerged: true),
new ChangeEntry("SomePath3", "SomeOriginalPath", ChangeEntryStatus.Modified),
new ChangeEntry("SomeConflictedPath4", "SomeOriginalPath", ChangeEntryStatus.Modified, unmerged: true),
new ChangeEntry("SomeConflictedPath5", "SomeOriginalPath", ChangeEntryStatus.Modified, unmerged: true)
};
var historyChanges = new List<IChangeEntry>
{
new ChangeEntry("HistoryItemPath", "HistoryItemOriginalPath", ChangeEntryStatus.Modified, true)
};
m_History = new List<IHistoryEntry>
{
new HistoryEntry("HistoryItemRevisionId", HistoryEntryStatus.Current,"HistoryItemAuthorName", "HistoryItemMessage", DateTimeOffset.Now, historyChanges)
};
}
/// <summary>
/// Safely delays a call onto the main thread.
/// </summary>
/// <param name="call">Call to delay.</param>
static void SafeDelayCall(Action call)
{
Task.Delay(2000).ContinueWith(_ => EditorApplication.delayCall += () => call());
}
public void SetChanges(List<IChangeEntry> changes)
{
m_Changes = changes;
NotifyChanges();
}
IReadOnlyList<IChangeEntry> CloneChanges()
{
return m_Changes.Select(item => item).ToList();
}
IReadOnlyList<IHistoryEntry> CloneHistory()
{
return m_History.Select(item => item).ToList();
}
void NotifyChanges()
{
UpdatedChangeList?.Invoke();
}
void NotifyHistory()
{
UpdatedHistoryEntries?.Invoke();
}
public bool GetRemoteRevisionAvailability()
{
return false;
}
public bool GetConflictedState()
{
return m_Changes.Any(e => e.Unmerged);
}
public IProgressInfo GetProgressState()
{
return new ProgressInfo();
}
public IErrorInfo GetErrorState()
{
throw new NotImplementedException();
}
public ProjectStatus GetProjectStatus()
{
throw new NotImplementedException();
}
public void RequestChangeList(Action<IReadOnlyList<IChangeEntry>> callback)
{
callback(CloneChanges());
}
public void RequestPublish(string message, IReadOnlyList<IChangeEntry> changes = null)
{
throw new NotImplementedException();
}
public void RequestHistoryEntry(string revisionId, Action<IHistoryEntry> callback)
{
SafeDelayCall(() =>
{
try
{
callback(CloneHistory().FirstOrDefault(e => e.RevisionId == revisionId));
}
catch (Exception e)
{
Debug.LogException(e);
callback(CloneHistory().FirstOrDefault(i => i.RevisionId == revisionId));
}
});
}
public void RequestHistoryPage(int offset, int pageSize, Action<IReadOnlyList<IHistoryEntry>> callback)
{
var safeSize = Math.Min(m_History.Count - offset, pageSize);
SafeDelayCall(() =>
{
try
{
Assert.Greater(m_History.Count, offset, "The offset should never be greater than the total number of history entries.");
callback(CloneHistory().ToList().GetRange(offset, safeSize));
}
catch (Exception e)
{
Debug.LogException(e);
callback(null);
}
});
}
public void RequestHistoryCount(Action<int?> callback)
{
SafeDelayCall(() => callback(m_History.Count));
}
public void RequestDiscard(IChangeEntry entry)
{
throw new NotImplementedException();
}
public void RequestBulkDiscard(IReadOnlyList<IChangeEntry> entries)
{
throw new NotImplementedException();
}
public void RequestDiffChanges(string path)
{
throw new NotImplementedException();
}
public bool SupportsRevert { get; } = false;
public void RequestRevert(string revisionId, IReadOnlyList<string> files)
{
throw new NotImplementedException();
}
public void RequestUpdateTo(string revisionId)
{
throw new NotImplementedException();
}
public void RequestRestoreTo(string revisionId)
{
throw new NotImplementedException();
}
public void RequestGoBackTo(string revisionId)
{
throw new NotImplementedException();
}
public void ClearError()
{
}
public void RequestShowConflictedDifferences(string path)
{
throw new NotImplementedException();
}
public void RequestChooseMerge(string path)
{
throw new NotImplementedException();
}
public void RequestChooseMine(string[] paths)
{
throw new NotImplementedException();
}
public void RequestChooseRemote(string[] paths)
{
throw new NotImplementedException();
}
public void RequestSync()
{
throw new NotImplementedException();
}
public void RequestCancelJob()
{
throw new NotImplementedException();
}
public void RequestTurnOnService()
{
throw new NotImplementedException();
}
public void ShowServicePage()
{
throw new NotImplementedException();
}
public void ShowLoginPage()
{
throw new NotImplementedException();
}
public void ShowNoSeatPage()
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c1a720a51e44604479a70a6a175aac0b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,191 @@
using System;
using System.Collections;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models.Enums;
using Unity.Cloud.Collaborate.Models.Providers;
using UnityEngine.TestTools;
namespace Unity.Cloud.Collaborate.Tests.Models
{
internal class StartModelTests
{
TestCollab m_Provider;
AsyncToCoroutine m_Atc;
[OneTimeSetUp]
public void OneTimeSetup()
{
m_Atc = new AsyncToCoroutine();
}
[SetUp]
public void Setup()
{
m_Provider = new TestCollab();
}
[TearDown]
public void TearDown()
{
m_Provider = null;
}
[UnityTest]
public IEnumerator TestWhenProjectBoundSavesAssets()
{
return m_Atc.Run(async () =>
{
var saveAssetsCallCount = 0;
//ensure we return true for isProjectBound
m_Provider.isProjectBoundTestImpl = () => ProjectStatus.Bound;
m_Provider.saveAssetsTestImpl = () => saveAssetsCallCount++;
saveAssetsCallCount.ShouldBe(0);
await m_Provider.TestRequestTurnOnService();
saveAssetsCallCount.ShouldBe(1, $"Expected {nameof(saveAssetsCallCount)} to be 1");
});
}
[UnityTest]
public IEnumerator TestWhenGenesisReturnsForbiddenShowsCredentialsError()
{
return m_Atc.Run(async () =>
{
var showCredentialsErrorCallCount = 0;
var putAsyncCallCount = 0;
//ensure we return true for isProjectBound
m_Provider.isProjectBoundTestImpl = () => ProjectStatus.Bound;
m_Provider.showCredentialsErrorTestImpl = () => showCredentialsErrorCallCount++;
m_Provider.putAsyncTestImpl = () =>
{
putAsyncCallCount++;
return Task.Run(() => new HttpResponseMessage(HttpStatusCode.Forbidden));
};
putAsyncCallCount.ShouldBe(0);
showCredentialsErrorCallCount.ShouldBe(0);
await m_Provider.TestRequestTurnOnService();
putAsyncCallCount.ShouldBe(1, $"Expected {nameof(putAsyncCallCount)} to be 1");
showCredentialsErrorCallCount.ShouldBe(1, $"Expected {nameof(showCredentialsErrorCallCount)} to be 1");
});
}
[UnityTest]
public IEnumerator TestsWhenGenesisReturnsErrorShowsGenericError()
{
return m_Atc.Run(async () =>
{
var showGeneralErrorCallCount = 0;
var putAsyncCallCount = 0;
//ensure we return true for isProjectBound
m_Provider.isProjectBoundTestImpl = () => ProjectStatus.Bound;
m_Provider.showGeneralErrorTestImpl = () =>
{
showGeneralErrorCallCount++;
};
m_Provider.putAsyncTestImpl = () =>
{
putAsyncCallCount++;
return Task.Run(() => new HttpResponseMessage(HttpStatusCode.NotFound));
};
putAsyncCallCount.ShouldBe(0);
showGeneralErrorCallCount.ShouldBe(0);
await m_Provider.TestRequestTurnOnService();
putAsyncCallCount.ShouldBe(1, $"Expected {nameof(putAsyncCallCount)} to be 1");
showGeneralErrorCallCount.ShouldBe(1, $"Expected {nameof(showGeneralErrorCallCount)} to be 1");
});
}
[UnityTest]
public IEnumerator TestWhenGenesisReturnsOkCallsTurnOnCollabInternal()
{
return m_Atc.Run(async () =>
{
var putAsyncCallCount = 0;
var turnOnCollabInternalCallCount = 0;
// Ensure we return true for isProjectBound.
m_Provider.isProjectBoundTestImpl = () => ProjectStatus.Bound;
m_Provider.turnOnCollabInternalTestImpl = () => turnOnCollabInternalCallCount++;
m_Provider.putAsyncTestImpl = () =>
{
putAsyncCallCount++;
return Task.Run(() => new HttpResponseMessage(HttpStatusCode.OK));
};
putAsyncCallCount.ShouldBe(0);
turnOnCollabInternalCallCount.ShouldBe(0);
await m_Provider.TestRequestTurnOnService();
putAsyncCallCount.ShouldBe(1, $"Expected {nameof(putAsyncCallCount)} to be 1");
turnOnCollabInternalCallCount.ShouldBe(1, $"Expected {nameof(turnOnCollabInternalCallCount)} to be 1");
});
}
class TestCollab : Collab
{
public Func<ProjectStatus> isProjectBoundTestImpl;
public Action saveAssetsTestImpl;
public Action turnOnCollabInternalTestImpl;
public Func<Task<HttpResponseMessage>> putAsyncTestImpl;
public Action showCredentialsErrorTestImpl;
public Action showGeneralErrorTestImpl;
public TestCollab()
{
isProjectBoundTestImpl = () => ProjectStatus.Unbound;
saveAssetsTestImpl = () => { };
turnOnCollabInternalTestImpl = () => { };
showCredentialsErrorTestImpl = () => { };
showGeneralErrorTestImpl = () => { };
putAsyncTestImpl = () => Task.Run(() => new HttpResponseMessage());
}
public async Task TestRequestTurnOnService()
{
await RequestTurnOnServiceInternal();
}
protected override Task<HttpResponseMessage> PutAsync(HttpClient client, string fullUrl, StringContent content)
{
return putAsyncTestImpl?.Invoke();
}
protected override void TurnOnCollabInternal()
{
turnOnCollabInternalTestImpl?.Invoke();
}
protected override void SaveAssets()
{
saveAssetsTestImpl?.Invoke();
}
public override ProjectStatus GetProjectStatus()
{
return isProjectBoundTestImpl?.Invoke() ?? ProjectStatus.Unbound;
}
protected override void ShowCredentialsError()
{
showCredentialsErrorTestImpl?.Invoke();
}
protected override void ShowGeneralError()
{
showGeneralErrorTestImpl?.Invoke();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 65dbc1a79b82e2b49884dcc702396733
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,192 @@
using System;
using System.Collections.Generic;
using Unity.Cloud.Collaborate.Models;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.UserInterface;
namespace Unity.Cloud.Collaborate.Tests.Models
{
internal class TestChangesModel : IChangesModel
{
public int UpdateEntryToggleCount;
public string UpdateEntryTogglePath;
public bool? UpdateEntryToggleValue;
public int GetToggledEntriesCount;
public string GetToggledEntriesQuery;
public int GetUntoggledEntriesCount;
public string GetUntoggledEntriesQuery;
public int GetAllEntriesCount;
public string GetAllEntriesQuery;
public int GetConflictedEntriesCount;
public string GetConflictedEntriesQuery;
public int RequestInitialDataCount;
public int RequestDiscardCount;
public IChangeEntry RequestDiscardEntry;
public int RequestBulkDiscardCount;
public IReadOnlyList<IChangeEntry> RequestBulkDiscardPaths;
public int RequestDiffCount;
public string RequestDiffPath;
public int RequestPublishCount;
public IReadOnlyList<IChangeEntry> RequestPublishList;
public IReadOnlyList<IChangeEntryData> UntoggledEntries = new List<IChangeEntryData>();
public IReadOnlyList<IChangeEntryData> ToggledEntries = new List<IChangeEntryData>();
public IReadOnlyList<IChangeEntryData> AllEntries = new List<IChangeEntryData>();
public IReadOnlyList<IChangeEntryData> ConflictedEntries = new List<IChangeEntryData>();
public event Action UpdatedChangeList = delegate { };
public event Action<bool> BusyStatusUpdated = delegate { };
public event Action OnUpdatedSelectedChanges = delegate { };
public event Action StateChanged = delegate { };
public string SavedRevisionSummary { get; set; } = "";
public string SavedSearchQuery { get; set; } = "";
public int ToggledCount => ToggledEntries.Count;
public int TotalCount => AllEntries.Count;
public int ConflictedCount => ConflictedEntries.Count;
public bool Conflicted => ConflictedCount != 0;
public bool Busy { get; set; }
public void TriggerUpdatedChangeList()
{
UpdatedChangeList();
}
public void TriggerBusyStatusUpdated(bool value)
{
BusyStatusUpdated(value);
}
public bool UpdateEntryToggle(string path, bool toggled)
{
UpdateEntryToggleCount++;
UpdateEntryTogglePath = path;
UpdateEntryToggleValue = toggled;
return false;
}
public IReadOnlyList<IChangeEntryData> GetToggledEntries(string query = null)
{
GetToggledEntriesCount++;
GetToggledEntriesQuery = query;
return ToggledEntries;
}
public IReadOnlyList<IChangeEntryData> GetUntoggledEntries(string query = null)
{
GetUntoggledEntriesCount++;
GetUntoggledEntriesQuery = query;
return UntoggledEntries;
}
public IReadOnlyList<IChangeEntryData> GetAllEntries(string query = null)
{
GetAllEntriesCount++;
GetAllEntriesQuery = query;
return AllEntries;
}
public IReadOnlyList<IChangeEntryData> GetConflictedEntries(string query = null)
{
GetConflictedEntriesCount++;
GetConflictedEntriesQuery = query;
return ConflictedEntries;
}
public void RequestInitialData()
{
RequestInitialDataCount++;
}
public void RequestDiffChanges(string path)
{
RequestDiffCount++;
RequestDiffPath = path;
}
public void RequestDiscard(IChangeEntry entry)
{
RequestDiscardCount++;
RequestDiscardEntry = entry;
}
public void RequestBulkDiscard(IReadOnlyList<IChangeEntry> paths)
{
RequestBulkDiscardCount++;
RequestBulkDiscardPaths = paths;
}
public void RequestPublish(string message, IReadOnlyList<IChangeEntry> changes = null)
{
RequestPublishCount++;
RequestPublishList = changes;
}
public void RequestShowConflictedDifferences(string path)
{
throw new NotImplementedException();
}
public void RequestChooseMerge(string path)
{
throw new NotImplementedException();
}
public void RequestChooseMine(string[] paths)
{
throw new NotImplementedException();
}
public void RequestChooseRemote(string[] paths)
{
throw new NotImplementedException();
}
internal class ChangeEntryData : IChangeEntryData
{
public IChangeEntry Entry { get; set; }
public bool Toggled { get; set; }
public bool All { get; set; }
public bool ToggleReadOnly { get; set; }
public bool Conflicted { get; set; }
}
public void OnStart()
{
throw new NotImplementedException();
}
public void OnStop()
{
throw new NotImplementedException();
}
public void RestoreState(IWindowCache cache)
{
throw new NotImplementedException();
}
public void SaveState(IWindowCache cache)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b25b386ca61a6d4d97a654fd3e5b96d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.UserInterface;
namespace Unity.Cloud.Collaborate.Tests.Models
{
internal class TestHistoryModel : IHistoryModel
{
public event Action HistoryListUpdated = delegate { };
public event Action<IReadOnlyList<IHistoryEntry>> HistoryListReceived = delegate { };
public event Action<IHistoryEntry> SelectedRevisionReceived = delegate { };
public event Action<bool> BusyStatusUpdated = delegate { };
public event Action<int?> EntryCountUpdated = delegate { };
public event Action StateChanged = delegate { };
public int RequestedPageOfRevisionsCount;
public int RequestedPageSize;
public int RequestedSingleRevisionCount;
[CanBeNull]
public string RequestedRevisionId;
public int RequestedEntryCountCount;
public int RequestedUpdateToCount;
[CanBeNull]
public string RequestedUpdateToRevisionId;
public int RequestedRestoreToCount;
[CanBeNull]
public string RequestedRestoreToRevisionId;
public int RequestedGoBackToCount;
[CanBeNull]
public string RequestedGoBackToRevisionId;
public int RequestedRevertCount;
[CanBeNull]
public string RequestedRevertRevisionId;
public int RequestedRevertFileCount;
public void SetNumberOfEntries(int count)
{
Assert.NotNull(EntryCountUpdated, "There should be an receiver for the entry number count event.");
EntryCountUpdated.Invoke(count);
}
public void TriggerUpdatedEntryListEvent()
{
Assert.NotNull(HistoryListUpdated, "There should be an receiver for the history list updated event.");
HistoryListUpdated();
}
public bool Busy { get; set; }
public int PageNumber { get; set; }
public string SelectedRevisionId { get; set; }
public string SavedRevisionId { get; set; }
public bool IsRevisionSelected => !string.IsNullOrEmpty(SelectedRevisionId);
public void RequestPageOfRevisions(int pageSize)
{
RequestedPageSize = pageSize;
RequestedPageOfRevisionsCount++;
}
public void RequestSingleRevision(string revisionId)
{
RequestedRevisionId = revisionId;
RequestedSingleRevisionCount++;
}
public void RequestEntryNumber()
{
RequestedEntryCountCount++;
}
public void RequestUpdateTo(string revisionId)
{
RequestedUpdateToCount++;
RequestedUpdateToRevisionId = revisionId;
}
public void RequestRestoreTo(string revisionId)
{
RequestedRestoreToCount++;
RequestedRestoreToRevisionId = revisionId;
}
public void RequestGoBackTo(string revisionId)
{
RequestedGoBackToCount++;
RequestedGoBackToRevisionId = revisionId;
}
public bool SupportsRevert { get; } = false;
public void RequestRevert(string revisionId, IReadOnlyList<string> files)
{
RequestedRevertCount++;
RequestedRevertRevisionId = revisionId;
RequestedRevertFileCount = files.Count;
}
public void OnStart()
{
throw new NotImplementedException();
}
public void OnStop()
{
throw new NotImplementedException();
}
public void RestoreState(IWindowCache cache)
{
throw new NotImplementedException();
}
public void SaveState(IWindowCache cache)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f56a99fa7c9121f46a7915e03de4d0a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,138 @@
using System;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.UserInterface;
namespace Unity.Cloud.Collaborate.Tests.Models
{
internal class TestMainModel : IMainModel
{
public int clearErrorCount;
public int requestSyncCount;
public int requestCancelJobCount;
public IHistoryModel historyModel = new TestHistoryModel();
public IChangesModel changesModel = new TestChangesModel();
public (string id, string text, Action backAction)? backNavigation;
public event Action<bool> ConflictStatusChange = delegate { };
public void TriggerConflictStatusChange(bool conflict)
{
ConflictStatusChange(conflict);
}
public event Action<bool> OperationStatusChange = delegate { };
public void TriggerOperationStatusChange(bool inProgress)
{
OperationStatusChange(inProgress);
}
public event Action<IProgressInfo> OperationProgressChange = delegate { };
public void TriggerOperationProgressChange(IProgressInfo progressInfo)
{
OperationProgressChange(progressInfo);
}
public event Action<IErrorInfo> ErrorOccurred = delegate { };
public void TriggerErrorOccurred(IErrorInfo errorInfo)
{
ErrorOccurred(errorInfo);
}
public event Action ErrorCleared = delegate { };
public void TriggerErrorCleared()
{
ErrorCleared();
}
public event Action<bool> RemoteRevisionsAvailabilityChange = delegate { };
public void TriggerRemoteRevisionsAvailabilityChange(bool available)
{
RemoteRevisionsAvailabilityChange(available);
}
public event Action<string> BackButtonStateUpdated = delegate { };
public void TriggerBackButtonStateUpdated(string backText)
{
BackButtonStateUpdated(backText);
}
public event Action StateChanged = delegate { };
public void TriggerStateChanged()
{
StateChanged();
}
public bool RemoteRevisionsAvailable { get; set; }
public bool Conflicted { get; set; }
public IProgressInfo ProgressInfo { get; set; }
public IErrorInfo ErrorInfo { get; set; }
public int CurrentTabIndex { get; set; }
public IHistoryModel ConstructHistoryModel()
{
return historyModel;
}
public IChangesModel ConstructChangesModel()
{
return changesModel;
}
public void ClearError()
{
clearErrorCount++;
}
public void RequestSync()
{
requestSyncCount++;
}
public void RequestCancelJob()
{
requestCancelJobCount++;
}
public (string id, string text, Action backAction)? GetBackNavigation()
{
return backNavigation;
}
public void RegisterBackNavigation(string id, string text, Action backAction)
{
Assert.IsNull(backNavigation);
backNavigation = (id, text, backAction);
}
public bool UnregisterBackNavigation(string id)
{
if (backNavigation == null || backNavigation.Value.id != id)
return false;
backNavigation = null;
return true;
}
public void OnStart()
{
throw new NotImplementedException();
}
public void OnStop()
{
throw new NotImplementedException();
}
public void RestoreState(IWindowCache cache)
{
throw new NotImplementedException();
}
public void SaveState(IWindowCache cache)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e47743db60d9e3e48b0a6fa8c0b95640
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models.Api;
using Unity.Cloud.Collaborate.Models.Enums;
using Unity.Cloud.Collaborate.Models.Structures;
namespace Unity.Cloud.Collaborate.Tests.Models
{
internal class TestSourceControlProvider : ISourceControlProvider
{
public int RequestedHistoryRevisionCount;
[CanBeNull]
public string RequestedHistoryRevisionId;
public int RequestedHistoryListCount;
public int? RequestedHistoryListOffset;
public int? RequestedHistoryListSize;
public int RequestedHistoryCountCount;
public int RequestedUpdateToCount;
[CanBeNull]
public string RequestedUpdateToRevisionId;
public int RequestedRestoreToCount;
[CanBeNull]
public string RequestedRestoreToRevisionId;
public int RequestedGoBackToCount;
[CanBeNull]
public string RequestedGoBackToRevisionId;
public int RequestedRevertCount;
[CanBeNull]
public string RequestedRevertRevisionId;
public int? RequestedRevertFileCount;
public int RequestedChangeListCount;
[CanBeNull]
public Action<IReadOnlyList<IChangeEntry>> RequestedChangeListCallback;
public int RequestedDiscardCount;
[CanBeNull]
public IChangeEntry RequestedDiscardEntry;
public int RequestedBulkDiscardCount;
[CanBeNull]
public IReadOnlyList<IChangeEntry> RequestedBulkDiscardPaths;
public int RequestedDiffChangesCount;
[CanBeNull]
public string RequestedDiffChangesPath;
public int RequestedPublishCount;
[CanBeNull]
public string RequestedPublishMessage;
[CanBeNull]
public IReadOnlyList<IChangeEntry> RequestedPublishList;
public bool RemoteRevisionAvailability = false;
public bool ConflictedState = false;
public event Action UpdatedChangeList = delegate { };
public event Action UpdatedHistoryEntries = delegate { };
public event Action<bool> UpdatedConflictState = delegate { };
public event Action<bool> UpdatedRemoteRevisionsAvailability = delegate { };
public event Action<ProjectStatus> UpdatedProjectStatus = delegate { };
public event Action<bool> UpdatedOperationStatus = delegate { };
public event Action<IProgressInfo> UpdatedOperationProgress = delegate { };
public event Action<IErrorInfo> ErrorOccurred = delegate { };
public event Action ErrorCleared = delegate { };
public event Action<IReadOnlyList<string>> UpdatedSelectedChangeList = delegate { };
public bool GetRemoteRevisionAvailability()
{
return RemoteRevisionAvailability;
}
public bool GetConflictedState()
{
return ConflictedState;
}
public IProgressInfo GetProgressState()
{
throw new NotImplementedException();
}
public IErrorInfo GetErrorState()
{
throw new NotImplementedException();
}
public ProjectStatus GetProjectStatus()
{
throw new NotImplementedException();
}
public void RequestChangeList(Action<IReadOnlyList<IChangeEntry>> callback)
{
RequestedChangeListCount++;
RequestedChangeListCallback = callback;
}
public void RequestPublish(string message, IReadOnlyList<IChangeEntry> changes = null)
{
RequestedPublishCount++;
RequestedPublishMessage = message;
RequestedPublishList = changes;
}
public void TriggerUpdatedHistoryEntries()
{
Assert.NotNull(UpdatedHistoryEntries, "There should be a listener registered.");
UpdatedHistoryEntries();
}
public void TriggerUpdatedChangeEntries()
{
Assert.NotNull(UpdatedHistoryEntries, "There should be a listener registered.");
UpdatedChangeList();
}
public void RequestHistoryEntry(string revisionId, Action<IHistoryEntry> callback)
{
RequestedHistoryRevisionCount++;
RequestedHistoryRevisionId = revisionId;
callback(null);
}
public void RequestHistoryPage(int offset, int pageSize, Action<IReadOnlyList<IHistoryEntry>> callback)
{
RequestedHistoryListCount++;
RequestedHistoryListOffset = offset;
RequestedHistoryListSize = pageSize;
callback(null);
}
public void RequestHistoryCount(Action<int?> callback)
{
RequestedHistoryCountCount++;
callback(null);
}
public void RequestDiscard(IChangeEntry entry)
{
RequestedDiscardCount++;
RequestedDiscardEntry = entry;
}
public void RequestBulkDiscard(IReadOnlyList<IChangeEntry> entries)
{
RequestedBulkDiscardCount++;
RequestedBulkDiscardPaths = entries;
}
public void RequestDiffChanges(string path)
{
RequestedDiffChangesCount++;
RequestedDiffChangesPath = path;
}
public bool SupportsRevert { get; } = false;
public void RequestRevert(string revisionId, IReadOnlyList<string> files)
{
RequestedRevertCount++;
RequestedRevertRevisionId = revisionId;
RequestedRevertFileCount = files.Count;
}
public void RequestUpdateTo(string revisionId)
{
RequestedUpdateToCount++;
RequestedUpdateToRevisionId = revisionId;
}
public void RequestRestoreTo(string revisionId)
{
RequestedRestoreToCount++;
RequestedRestoreToRevisionId = revisionId;
}
public void RequestGoBackTo(string revisionId)
{
RequestedGoBackToCount++;
RequestedGoBackToRevisionId = revisionId;
}
public void ClearError()
{
}
public void RequestShowConflictedDifferences(string path)
{
throw new NotImplementedException();
}
public void RequestChooseMerge(string path)
{
throw new NotImplementedException();
}
public void RequestChooseMine(string[] paths)
{
throw new NotImplementedException();
}
public void RequestChooseRemote(string[] paths)
{
throw new NotImplementedException();
}
public void RequestSync()
{
throw new NotImplementedException();
}
public void RequestCancelJob()
{
throw new NotImplementedException();
}
public void RequestTurnOnService()
{
throw new NotImplementedException();
}
public void ShowServicePage()
{
throw new NotImplementedException();
}
public void ShowLoginPage()
{
throw new NotImplementedException();
}
public void ShowNoSeatPage()
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb18ae523e202db40a866e7813fa2c0c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,69 @@
using System;
using Unity.Cloud.Collaborate.Models;
using Unity.Cloud.Collaborate.Models.Enums;
using Unity.Cloud.Collaborate.UserInterface;
namespace Unity.Cloud.Collaborate.Tests.Models
{
internal class TestStartModel : IStartModel
{
public int requestTurnOnServiceCount;
public int showServicePageCount;
public int showLoginPageCount;
public int showNoSeatPageCount;
public event Action StateChanged = delegate { };
public void TriggerStateChanged()
{
StateChanged();
}
public event Action<ProjectStatus> ProjectStatusChanged = delegate { };
public void TriggerProjectStatusChanged(ProjectStatus status)
{
ProjectStatusChanged(status);
}
public ProjectStatus ProjectStatus { get; set; }
public void OnStart()
{
throw new NotImplementedException();
}
public void OnStop()
{
throw new NotImplementedException();
}
public void RestoreState(IWindowCache cache)
{
throw new NotImplementedException();
}
public void SaveState(IWindowCache cache)
{
throw new NotImplementedException();
}
public void RequestTurnOnService()
{
requestTurnOnServiceCount++;
}
public void ShowServicePage()
{
showServicePageCount++;
}
public void ShowLoginPage()
{
showLoginPageCount++;
}
public void ShowNoSeatPage()
{
showNoSeatPageCount++;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 49d15206774f47cab3c22a97f27bf8ec
timeCreated: 1576186334

View file

@ -0,0 +1,24 @@
using Unity.Cloud.Collaborate.UserInterface;
namespace Unity.Cloud.Collaborate.Tests.Models
{
internal class TestWindowCache : IWindowCache
{
public void Clear()
{
SimpleSelectedItems = default;
RevisionSummary = default;
ChangesSearchValue = default;
SelectedHistoryRevision = default;
HistoryPageNumber = default;
TabIndex = default;
}
public SelectedItemsDictionary SimpleSelectedItems { get; set; }
public string RevisionSummary { get; set; }
public string ChangesSearchValue { get; set; }
public string SelectedHistoryRevision { get; set; }
public int HistoryPageNumber { get; set; }
public int TabIndex { get; set; }
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: acd046f16a9a499699c470bf320ab6be
timeCreated: 1574115275

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 38fe47e80ef3d524d8c3508224f6cffe
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,341 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Tests.Models;
using Unity.Cloud.Collaborate.Views;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
public class ChangesPresenterTests
{
class TestableChangesPresenter : ChangesPresenter
{
public TestableChangesPresenter([NotNull] IChangesView view, [NotNull] IChangesModel model, [NotNull] IMainModel mainModel)
: base(view, model, mainModel)
{
}
public void NotifyOnRemoteRevisionsAvailabilityChange(bool available)
{
base.OnRemoteRevisionsAvailabilityChange(available);
}
public void NotifyOnUpdatedChangeList()
{
base.OnUpdatedChangeList();
}
public void NotifyOnUpdatedPartiallySelectedChanges()
{
base.OnUpdatedPartiallySelectedChanges();
}
public void NotifyOnConflictStatusChange(bool conflicted)
{
base.OnConflictStatusChange(conflicted);
}
}
TestChangesView m_View;
TestChangesModel m_Model;
TestMainModel m_MainModel;
TestableChangesPresenter m_Presenter;
[SetUp]
public void Setup()
{
m_View = new TestChangesView();
m_Model = new TestChangesModel();
m_MainModel = new TestMainModel();
m_Presenter = new TestableChangesPresenter(m_View, m_Model, m_MainModel);
}
[TearDown]
public void TearDown()
{
m_Presenter.Stop();
m_View = null;
m_Model = null;
m_MainModel = null;
m_Presenter = null;
}
[Test]
public void TestToggledCountValue()
{
m_Presenter.Start();
m_Model.ToggledEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") },
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path2") }
};
Assert.AreEqual(2, m_Presenter.ToggledCount);
}
[Test]
public void TestTotalCountValue()
{
m_Presenter.Start();
m_Model.AllEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") },
new TestChangesModel.ChangeEntryData { Toggled = false, Entry = new ChangeEntry("path2") }
};
Assert.AreEqual(2, m_Presenter.TotalCount);
}
[Test]
public void TestConflictedCountValue()
{
m_Presenter.Start();
m_Model.ConflictedEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData
{
Conflicted = true,
Entry = new ChangeEntry("path", null, ChangeEntryStatus.Unmerged, false, true)
},
new TestChangesModel.ChangeEntryData
{
Conflicted = true,
Entry = new ChangeEntry("path2", null, ChangeEntryStatus.Unmerged, false, true)
}
};
Assert.AreEqual(2, m_Presenter.ConflictedCount);
}
[Test]
public void TestSearchingValue()
{
m_Presenter.Start();
m_Model.SavedSearchQuery = "test";
Assert.IsTrue(m_Presenter.Searching);
m_Model.SavedSearchQuery = "";
Assert.IsFalse(m_Presenter.Searching);
}
[Test]
public void TestSettingEntryToggle()
{
m_Presenter.Start();
const string path = "path";
const bool value = true;
m_Presenter.UpdateEntryToggle(path, value);
Assert.AreEqual(1, m_Model.UpdateEntryToggleCount);
Assert.AreEqual(path, m_Model.UpdateEntryTogglePath);
Assert.AreEqual(value, m_Model.UpdateEntryToggleValue);
}
[Test]
public void TestRequestPublish()
{
m_Presenter.Start();
m_Model.SavedSearchQuery = "";
m_Model.ToggledEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") }
};
m_Presenter.RequestPublish();
Assert.AreEqual(1, m_Model.GetToggledEntriesCount);
Assert.AreEqual(1, m_Model.RequestPublishCount);
Assert.AreEqual(1, m_Model.RequestPublishList.Count);
}
[Test]
public void TestRequestPublishFailWhenSearching()
{
m_Presenter.Start();
m_Model.SavedSearchQuery = "some query";
Assert.Catch(() => m_Presenter.RequestPublish());
}
[Test]
public void TestRequestDiscard()
{
m_Presenter.Start();
const string path = "path";
var entry = new ChangeEntry(path);
m_Presenter.RequestDiscard(entry);
Assert.AreEqual(1, m_Model.RequestDiscardCount);
Assert.AreEqual(path, m_Model.RequestDiscardEntry.Path);
// Ensure it created a dialogue
Assert.AreEqual(1, m_View.DisplayDialogueCount);
}
[Test]
public void TestRequestDiffChanges()
{
m_Presenter.Start();
const string path = "path";
m_Presenter.RequestDiffChanges(path);
Assert.AreEqual(1, m_Model.RequestDiffCount);
Assert.AreEqual(path, m_Model.RequestDiffPath);
}
[Test]
public void TestSetSearchQuery()
{
m_Presenter.Start();
Assert.AreEqual(1, m_View.SetSearchQueryCount);
const string query = "path Path ";
m_Presenter.SetSearchQuery(query);
Assert.AreEqual(query.Trim().ToLower(), m_Model.SavedSearchQuery);
Assert.AreEqual(2, m_View.SetSearchQueryCount);
Assert.AreEqual(query, m_View.SetSearchQueryValue);
}
[Test]
public void TestHavingSearchQueryDisablesPublish()
{
m_Presenter.Start();
m_Model.ToggledEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") }
};
// Base case
m_Presenter.SetSearchQuery("");
Assert.AreEqual(1, m_View.SetPublishEnabledCount);
Assert.AreEqual(true, m_View.SetPublishEnabledValue);
// Base to disabled case
m_Presenter.SetSearchQuery("query");
Assert.AreEqual(2, m_View.SetPublishEnabledCount);
Assert.AreEqual(false, m_View.SetPublishEnabledValue);
Assert.IsNotNull(m_View.SetPublishEnabledReason);
// Disabled back to base case.
m_Presenter.SetSearchQuery("");
Assert.AreEqual(3, m_View.SetPublishEnabledCount);
Assert.AreEqual(true, m_View.SetPublishEnabledValue);
}
[Test]
public void TestHavingConflictsDisablesPublish()
{
m_Model.ToggledEntries = new List<IChangeEntryData>()
{
new TestChangesModel.ChangeEntryData
{
Entry = new ChangeEntry("path", null, ChangeEntryStatus.Modified)
}
};
// Base case
m_Presenter.Start();
m_Model.ConflictedEntries = new List<IChangeEntryData>();
m_Model.TriggerUpdatedChangeList();
Assert.AreEqual(1, m_View.SetPublishEnabledCount);
Assert.AreEqual(true, m_View.SetPublishEnabledValue);
// Disable
m_Model.ConflictedEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData
{
Conflicted = true,
Entry = new ChangeEntry("path", null, ChangeEntryStatus.Unmerged, false, true)
}
};
m_Model.TriggerUpdatedChangeList();
Assert.AreEqual(2, m_View.SetPublishEnabledCount);
Assert.AreEqual(false, m_View.SetPublishEnabledValue);
Assert.IsNotNull(m_View.SetPublishEnabledReason);
// Re enabled
m_Model.ConflictedEntries = new List<IChangeEntryData>();
m_Model.TriggerUpdatedChangeList();
Assert.AreEqual(3, m_View.SetPublishEnabledCount);
Assert.AreEqual(true, m_View.SetPublishEnabledValue);
}
[Test]
public void TestSetRevisionService()
{
m_Presenter.Start();
Assert.AreEqual(1, m_View.SetRevisionSummaryCount);
const string summary = "summary";
m_Presenter.SetRevisionSummary(summary);
Assert.AreEqual(summary, m_Model.SavedRevisionSummary);
Assert.AreEqual(2, m_View.SetRevisionSummaryCount);
Assert.AreEqual(summary, m_View.SetRevisionSummaryValue);
}
[Test]
public void TestReceivingBusyMessage()
{
m_Presenter.Start();
// Sent initial status on start
Assert.AreEqual(1, m_View.SetBusyStatusCount);
Assert.AreEqual(false, m_View.SetBusyStatusValue);
// Test values once events called:
m_Model.TriggerBusyStatusUpdated(true);
Assert.AreEqual(2, m_View.SetBusyStatusCount);
Assert.AreEqual(true, m_View.SetBusyStatusValue);
m_Model.TriggerBusyStatusUpdated(false);
Assert.AreEqual(3, m_View.SetBusyStatusCount);
Assert.AreEqual(false, m_View.SetBusyStatusValue);
}
[Test]
public void TestOnUpdatedChangeListUpdatesPublishButton()
{
m_Presenter.Start();
m_Model.ToggledEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") },
new TestChangesModel.ChangeEntryData { Toggled = false, Entry = new ChangeEntry("path2") }
};
m_Presenter.NotifyOnUpdatedChangeList();
Assert.AreEqual(true, m_View.SetPublishEnabledValue);
}
[Test]
public void TestOnPartialChangesUpdatesPublishButton()
{
m_Presenter.Start();
m_Model.ToggledEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") },
new TestChangesModel.ChangeEntryData { Toggled = false, Entry = new ChangeEntry("path2") }
};
m_Presenter.NotifyOnUpdatedPartiallySelectedChanges();
Assert.AreEqual(true, m_View.SetPublishEnabledValue);
}
[Test]
public void TestOnRemoteRevisionsAvailabilityChangeUpdatesPublishButton()
{
m_Presenter.Start();
m_Model.ToggledEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") },
new TestChangesModel.ChangeEntryData { Toggled = false, Entry = new ChangeEntry("path2") }
};
m_MainModel.RemoteRevisionsAvailable = true;
m_Presenter.NotifyOnRemoteRevisionsAvailabilityChange(true);
Assert.AreEqual(false, m_View.SetPublishEnabledValue);
}
[Test]
public void TestOnConflictStatusChangeUpdatesPublishButton()
{
m_Presenter.Start();
m_Model.ToggledEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData { Toggled = true, Entry = new ChangeEntry("path") },
new TestChangesModel.ChangeEntryData { Toggled = false, Entry = new ChangeEntry("path2") }
};
m_Model.ConflictedEntries = new List<IChangeEntryData>
{
new TestChangesModel.ChangeEntryData
{
Conflicted = true,
Entry = new ChangeEntry("path", null, ChangeEntryStatus.Unmerged, false, true)
}
};
m_Presenter.NotifyOnConflictStatusChange(true);
Assert.AreEqual(false, m_View.SetPublishEnabledValue);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 27c4708da6102f346a800846ab2a1e47
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Tests.Models;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
public class HistoryPresenterTests
{
TestHistoryView m_View;
TestHistoryModel m_HistoryModel;
TestMainModel m_MainModel;
HistoryPresenter m_Presenter;
[SetUp]
public void Setup()
{
m_View = new TestHistoryView();
m_HistoryModel = new TestHistoryModel();
m_MainModel = new TestMainModel();
m_Presenter = new HistoryPresenter(m_View, m_HistoryModel, m_MainModel);
}
[TearDown]
public void TearDown()
{
m_Presenter.Stop();
m_View = null;
m_HistoryModel = null;
m_Presenter = null;
}
[Test]
public void TestStartCall()
{
m_Presenter.Start();
// Clear box testing here
Assert.AreEqual(m_HistoryModel.Busy, m_View.BusyStatus);
Assert.AreEqual(1, m_HistoryModel.RequestedEntryCountCount);
Assert.AreEqual(1, m_HistoryModel.RequestedPageOfRevisionsCount);
Assert.AreEqual(0, m_HistoryModel.RequestedSingleRevisionCount);
}
[Test]
public void TestStartWithSavedRevisionCall()
{
const string savedRevisionId = "123";
m_HistoryModel.SavedRevisionId = savedRevisionId;
m_Presenter.Start();
// Clear box testing here
Assert.AreEqual(m_HistoryModel.Busy, m_View.BusyStatus);
Assert.AreEqual(1, m_HistoryModel.RequestedEntryCountCount);
Assert.AreEqual(0, m_HistoryModel.RequestedPageOfRevisionsCount);
Assert.AreEqual(1, m_HistoryModel.RequestedSingleRevisionCount);
Assert.AreEqual(savedRevisionId, m_HistoryModel.RequestedRevisionId);
}
[Test]
public void TestReceivingUpdateEvent()
{
m_Presenter.Start();
// Clear box testing here
m_HistoryModel.TriggerUpdatedEntryListEvent();
Assert.AreEqual(2, m_HistoryModel.RequestedEntryCountCount);
Assert.AreEqual(2, m_HistoryModel.RequestedPageOfRevisionsCount);
Assert.AreEqual(0, m_HistoryModel.RequestedSingleRevisionCount);
}
[Test]
public void TestReceivingUpdateEventWithSelection()
{
const string selectedRevisionId = "123";
m_HistoryModel.SelectedRevisionId = selectedRevisionId;
m_Presenter.Start();
// Clear box testing here
m_HistoryModel.TriggerUpdatedEntryListEvent();
Assert.AreEqual(2, m_HistoryModel.RequestedEntryCountCount);
Assert.AreEqual(2, m_HistoryModel.RequestedSingleRevisionCount);
}
[Test]
public void TestReceivingEntryCount()
{
m_Presenter.Start();
m_HistoryModel.PageNumber = 1;
m_HistoryModel.SetNumberOfEntries(HistoryPresenter.pageSize * 2 + 1);
Assert.AreEqual(2, m_View.MaxPage);
Assert.AreEqual(1, m_View.Page);
}
[Test]
public void TestPreviousPageCall()
{
m_Presenter.Start();
m_HistoryModel.PageNumber = 1;
m_Presenter.PrevPage();
Assert.AreEqual(HistoryPresenter.pageSize, m_HistoryModel.RequestedPageSize, "Page size should match given value");
Assert.AreEqual(0, m_HistoryModel.PageNumber, "Requesting previous page should request previous page.");
}
[Test]
public void TestPreviousPageCallOnZero()
{
m_Presenter.Start();
m_HistoryModel.PageNumber = 0;
m_Presenter.PrevPage();
Assert.AreEqual(HistoryPresenter.pageSize, m_HistoryModel.RequestedPageSize, "Page size should match given value");
Assert.AreEqual(0, m_HistoryModel.PageNumber, "Requesting previous page on page zero shouldn't stay at zero.");
}
[Test]
public void TestNextPageCall()
{
m_Presenter.Start();
m_HistoryModel.PageNumber = 0;
m_HistoryModel.SetNumberOfEntries(HistoryPresenter.pageSize * 2);
m_Presenter.NextPage();
Assert.AreEqual(HistoryPresenter.pageSize, m_HistoryModel.RequestedPageSize, "Page size should match given value");
Assert.AreEqual(1, m_HistoryModel.PageNumber, "Requesting previous page should request next page.");
}
[Test]
public void TestNextPageCallOnZero()
{
m_Presenter.Start();
m_HistoryModel.PageNumber = 1;
m_HistoryModel.SetNumberOfEntries(HistoryPresenter.pageSize * 2);
m_Presenter.NextPage();
Assert.AreEqual(HistoryPresenter.pageSize, m_HistoryModel.RequestedPageSize, "Page size should match given value");
Assert.AreEqual(1, m_HistoryModel.PageNumber, "Requesting next page on max page should not change the page.");
}
[Test]
public void TestSetSelectedRevisionId()
{
const string selectedRevisionId = "123";
m_Presenter.Start();
m_Presenter.SelectedRevisionId = selectedRevisionId;
Assert.AreEqual(selectedRevisionId, m_HistoryModel.RequestedRevisionId);
}
[Test]
public void TestGotoCall()
{
const string revisionId = "123";
m_Presenter.Start();
var status = HistoryEntryStatus.Ahead;
m_Presenter.RequestGoto(revisionId, status);
Assert.AreEqual(1, m_HistoryModel.RequestedUpdateToCount);
Assert.AreEqual(revisionId, m_HistoryModel.RequestedUpdateToRevisionId);
status = HistoryEntryStatus.Current;
m_Presenter.RequestGoto(revisionId, status);
Assert.AreEqual(1, m_HistoryModel.RequestedRestoreToCount);
Assert.AreEqual(revisionId, m_HistoryModel.RequestedRestoreToRevisionId);
status = HistoryEntryStatus.Behind;
m_Presenter.RequestGoto(revisionId, status);
Assert.AreEqual(1, m_HistoryModel.RequestedGoBackToCount);
Assert.AreEqual(revisionId, m_HistoryModel.RequestedGoBackToRevisionId);
}
[Test]
public void TestRevertCall()
{
const string revisionId = "123";
m_Presenter.Start();
m_Presenter.RequestRevert(revisionId, new List<string> { "a", "b", "c" });
Assert.AreEqual(1, m_HistoryModel.RequestedRevertCount);
Assert.AreEqual(revisionId, m_HistoryModel.RequestedRevertRevisionId);
Assert.AreEqual(3, m_HistoryModel.RequestedRevertFileCount);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f5d8073410f83d479361cd2b45bcf60
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,128 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Tests.Models;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
public class MainPresenterTests
{
TestMainView m_View;
TestMainModel m_MainModel;
MainPresenter m_Presenter;
[SetUp]
public void Setup()
{
m_View = new TestMainView();
m_MainModel = new TestMainModel();
m_Presenter = new MainPresenter(m_View, m_MainModel);
}
[TearDown]
public void TearDown()
{
m_Presenter.Stop();
m_View = null;
m_MainModel = null;
m_Presenter = null;
}
[Test]
public void TestBackNavigation()
{
m_Presenter.Start();
var called = false;
m_MainModel.backNavigation = ("test", "test-text", () => called = true);
m_Presenter.NavigateBack();
Assert.IsTrue(called);
Assert.IsNull(m_MainModel.backNavigation);
}
[Test]
public void TestBackNavigationWithNull()
{
m_Presenter.Start();
m_MainModel.backNavigation = null;
m_Presenter.NavigateBack();
Assert.IsNull(m_MainModel.backNavigation);
}
[Test]
public void TestAssigningPresenters()
{
m_Presenter.Start();
var changesView = new TestChangesView();
m_Presenter.AssignChangesPresenter(changesView);
Assert.IsNotNull(changesView.Presenter);
var historyView = new TestHistoryView();
m_Presenter.AssignHistoryPresenter(historyView);
Assert.IsNotNull(historyView.Presenter);
}
[Test]
public void TestCancellingJob()
{
m_Presenter.Start();
m_Presenter.RequestCancelJob();
Assert.AreEqual(1, m_MainModel.requestCancelJobCount);
}
[Test]
public void TestSettingTabIndex()
{
m_Presenter.Start();
const int newVal = 5;
m_Presenter.UpdateTabIndex(newVal);
Assert.AreEqual(newVal, m_MainModel.CurrentTabIndex);
}
[Test]
public void TestStartingWithJobInProgress()
{
m_MainModel.ProgressInfo = new ProgressInfo("test", "test", 50, 20);
m_Presenter.Start();
Assert.IsTrue(m_View.inProgress);
Assert.IsNotNull(m_View.progress);
}
[Test]
public void TestStartingWithError()
{
const string message = "test message";
m_MainModel.ErrorInfo = new ErrorInfo(20, 1, (int)ErrorInfoBehavior.Alert, message, "test", "20");
m_Presenter.Start();
Assert.AreEqual(1, m_View.alerts.Count);
Assert.AreEqual(message, m_View.alerts.First().Value.message);
}
[Test]
public void TestReceivingStateChange()
{
const string message = "test message";
const int tabIndex = 67;
m_Presenter.Start();
m_MainModel.backNavigation = ("id", message, () => { });
m_MainModel.CurrentTabIndex = tabIndex;
m_MainModel.TriggerStateChanged();
Assert.AreEqual(message, m_View.backNavigation);
Assert.AreEqual(tabIndex, m_View.tabIndex);
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c27224849b8648b991691de4f0c90456
timeCreated: 1576178835

View file

@ -0,0 +1,94 @@
using NUnit.Framework;
using Unity.Cloud.Collaborate.Models.Enums;
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Tests.Models;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
internal class StartPresenterTests
{
TestStartView m_View;
TestStartModel m_Model;
StartPresenter m_Presenter;
[SetUp]
public void Setup()
{
m_View = new TestStartView();
m_Model = new TestStartModel();;
m_Presenter = new StartPresenter(m_View, m_Model);
}
[TearDown]
public void TearDown()
{
m_Presenter.Stop();
m_View = null;
m_Model = null;
m_Presenter = null;
}
[Test]
public void TestRequestingStart()
{
m_Presenter.Start();
m_Model.ProjectStatus = ProjectStatus.Bound;
m_Presenter.RequestStart();
Assert.AreEqual(1, m_Model.requestTurnOnServiceCount);
m_Model.ProjectStatus = ProjectStatus.Unbound;
m_Presenter.RequestStart();
Assert.AreEqual(1, m_Model.showServicePageCount);
m_Model.ProjectStatus = ProjectStatus.LoggedOut;
m_Presenter.RequestStart();
Assert.AreEqual(1, m_Model.showLoginPageCount);
m_Model.ProjectStatus = ProjectStatus.NoSeat;
m_Presenter.RequestStart();
Assert.AreEqual(1, m_Model.showNoSeatPageCount);
}
[Test]
public void TestUpdatingProjectStatus()
{
m_Presenter.Start();
m_Model.TriggerProjectStatusChanged(ProjectStatus.Bound);
Assert.IsTrue(m_View.buttonVisible);
m_Model.TriggerProjectStatusChanged(ProjectStatus.Unbound);
Assert.IsTrue(m_View.buttonVisible);
m_Model.TriggerProjectStatusChanged(ProjectStatus.LoggedOut);
Assert.IsTrue(m_View.buttonVisible);
m_Model.TriggerProjectStatusChanged(ProjectStatus.NoSeat);
Assert.IsTrue(m_View.buttonVisible);
m_Model.TriggerProjectStatusChanged(ProjectStatus.Loading);
Assert.IsFalse(m_View.buttonVisible);
m_Model.TriggerProjectStatusChanged(ProjectStatus.Offline);
Assert.IsFalse(m_View.buttonVisible);
m_Model.TriggerProjectStatusChanged(ProjectStatus.Maintenance);
Assert.IsFalse(m_View.buttonVisible);
m_Model.TriggerProjectStatusChanged(ProjectStatus.Ready);
Assert.IsFalse(m_View.buttonVisible);
}
[Test]
public void TestStateChange()
{
m_Presenter.Start();
m_Model.ProjectStatus = ProjectStatus.Bound;
m_Model.TriggerStateChanged();
Assert.IsTrue(m_View.buttonVisible);
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 485ab142ed644e479a8eb9a8137b8461
timeCreated: 1576186961

View file

@ -0,0 +1,94 @@
using System.Collections.Generic;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Views;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
internal class TestChangesView : IChangesView
{
public int SetBusyStatusCount;
public bool? SetBusyStatusValue;
public int SetSearchQueryCount;
public string SetSearchQueryValue;
public int SetRevisionSummaryCount;
public string SetRevisionSummaryValue;
public int SetConflictsCount;
public IReadOnlyList<IChangeEntryData> SetConflictsValue;
public int SetChangesCount;
public IReadOnlyList<IChangeEntryData> SetChangesValue;
public int SetToggledCountCount;
public int? SetToggledCountValue;
public int SetPublishEnabledCount;
public bool? SetPublishEnabledValue;
public string SetPublishEnabledReason;
public int DisplayDialogueCount;
public IChangesPresenter Presenter { get; set; }
public void SetBusyStatus(bool busy)
{
SetBusyStatusCount++;
SetBusyStatusValue = busy;
}
public void SetSearchQuery(string query)
{
SetSearchQueryCount++;
SetSearchQueryValue = query;
}
public void SetRevisionSummary(string message)
{
SetRevisionSummaryCount++;
SetRevisionSummaryValue = message;
}
public void SetConflicts(IReadOnlyList<IChangeEntryData> list)
{
SetConflictsCount++;
SetConflictsValue = list;
}
public void SetChanges(IReadOnlyList<IChangeEntryData> list)
{
SetChangesCount++;
SetChangesValue = list;
}
public void SetToggledCount(int count)
{
SetToggledCountCount++;
SetToggledCountValue = count;
}
public void SetPublishEnabled(bool enabled, string reason = null)
{
SetPublishEnabledCount++;
SetPublishEnabledValue = enabled;
SetPublishEnabledReason = reason;
}
public bool DisplayDialogue(string title, string message, string affirmative)
{
DisplayDialogueCount++;
return true;
}
public bool DisplayDialogue(string title, string message, string affirmative, string negative)
{
DisplayDialogueCount++;
return true;
}
public void SetSelectedChanges()
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 85a8810f7371b644186b2bbc0fb8bc17
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,72 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Models.Structures;
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Views;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
internal class TestHistoryView : IHistoryView
{
public IHistoryPresenter Presenter { get; set; }
public bool DialogueReturnValue = true;
public bool? BusyStatus;
public int? Page;
public int? MaxPage;
[CanBeNull]
public IHistoryEntry ReceivedEntry;
[CanBeNull]
public string DialogueTitle;
[CanBeNull]
public string DialogueMessage;
[CanBeNull]
public string DialogueAffirmative;
[CanBeNull]
public string DialogueNegative;
[CanBeNull]
public IReadOnlyList<IHistoryEntry> ReceivedList;
public void SetBusyStatus(bool busy)
{
BusyStatus = busy;
}
public void SetHistoryList(IReadOnlyList<IHistoryEntry> list)
{
ReceivedList = list;
ReceivedEntry = null;
}
public void SetPage(int page, int max)
{
Page = page;
MaxPage = max;
}
public void SetSelection(IHistoryEntry entry)
{
ReceivedEntry = entry;
ReceivedList = null;
}
public bool DisplayDialogue(string title, string message, string affirmative)
{
DialogueTitle = title;
DialogueMessage = message;
DialogueAffirmative = affirmative;
DialogueNegative = null;
return DialogueReturnValue;
}
public bool DisplayDialogue(string title, string message, string affirmative, string negative)
{
DialogueTitle = title;
DialogueMessage = message;
DialogueAffirmative = affirmative;
DialogueNegative = negative;
return DialogueReturnValue;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4d82f3cb1859dfe4fb3e5d83610c264c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using NUnit.Framework;
using Unity.Cloud.Collaborate.Components;
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Views;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
internal class TestMainView : IMainView
{
public int? tabIndex;
public bool inProgress;
public (string title, string details, int percentage, int completed, int total, bool isPercentage, bool canCancel)? progress;
[CanBeNull]
public string backNavigation;
public IMainPresenter Presenter { get; set; }
public Dictionary<string, (string id, AlertBox.AlertLevel level, string message, (string text, Action action)? button)> alerts = new Dictionary<string, (string id, AlertBox.AlertLevel level, string message, (string text, Action action)? button)>();
public void AddAlert(string id, AlertBox.AlertLevel level, string message, (string text, Action action)? button = null)
{
alerts[id] = (id, level, message, button);
}
public void RemoveAlert(string id)
{
alerts.Remove(id);
}
public void SetTab(int index)
{
tabIndex = index;
}
public void AddOperationProgress()
{
Assert.IsFalse(inProgress);
inProgress = true;
}
public void RemoveOperationProgress()
{
Assert.IsTrue(inProgress);
inProgress = false;
}
public void SetOperationProgress(string title, string details, int percentage, int completed, int total, bool isPercentage, bool canCancel)
{
progress = (title, details, percentage, completed, total, isPercentage, canCancel);
}
public void ClearBackNavigation()
{
backNavigation = null;
}
public void DisplayBackNavigation(string text)
{
backNavigation = text;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 63ffed391ffc4e11949711d888affd00
timeCreated: 1576178951

View file

@ -0,0 +1,21 @@
using Unity.Cloud.Collaborate.Presenters;
using Unity.Cloud.Collaborate.Views;
namespace Unity.Cloud.Collaborate.Tests.Presenters
{
internal class TestStartView : IStartView
{
public bool buttonVisible;
public IStartPresenter Presenter { get; set; }
public string Text { get; set; }
public string ButtonText { get; set; }
public void SetButtonVisible(bool isVisible)
{
buttonVisible = isVisible;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c26636c25de34fd1b5d32fd8fdb9b47d
timeCreated: 1576186207

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 62b5cc1364fceb24a9f76919757db06a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,147 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
namespace Unity.Cloud.Collaborate.Tests
{
public class CoroutineSynchronizationContext : SynchronizationContext
{
const int k_AwqInitialCapacity = 20;
readonly Queue<WorkRequest> m_AsyncWorkQueue = new Queue<WorkRequest>(k_AwqInitialCapacity);
readonly int m_MainThreadId = Thread.CurrentThread.ManagedThreadId;
// Send will process the call synchronously. If the call is processed on the main thread, we'll invoke it
// directly here. If the call is processed on another thread it will be queued up like POST to be executed
// on the main thread and it will wait. Once the main thread processes the work we can continue
public override void Send(SendOrPostCallback callback, object state)
{
if (m_MainThreadId == Thread.CurrentThread.ManagedThreadId)
{
callback(state);
}
else
{
using (var waitHandle = new ManualResetEvent(false))
{
lock (m_AsyncWorkQueue)
{
m_AsyncWorkQueue.Enqueue(new WorkRequest(callback, state, waitHandle));
}
waitHandle.WaitOne();
}
}
}
// Post will add the call to a task list to be executed later on the main thread then work will continue asynchronously
public override void Post(SendOrPostCallback callback, object state)
{
lock (m_AsyncWorkQueue)
{
m_AsyncWorkQueue.Enqueue(new WorkRequest(callback, state));
}
}
// Exec will execute tasks off the task list
public void Exec()
{
lock (m_AsyncWorkQueue)
{
var workCount = m_AsyncWorkQueue.Count;
for (var i = 0; i < workCount; i++)
{
var work = m_AsyncWorkQueue.Dequeue();
work.Invoke();
}
}
}
struct WorkRequest
{
readonly SendOrPostCallback m_DelegateCallback;
readonly object m_DelegateState;
readonly ManualResetEvent m_WaitHandle;
public WorkRequest(SendOrPostCallback callback, object state, ManualResetEvent waitHandle = null)
{
m_DelegateCallback = callback;
m_DelegateState = state;
m_WaitHandle = waitHandle;
}
public void Invoke()
{
m_DelegateCallback(m_DelegateState);
m_WaitHandle?.Set();
}
}
}
public class AsyncToCoroutine
{
readonly CoroutineSynchronizationContext m_Context;
readonly bool m_Cleanup;
public Func<Task> Before { get; set; }
public Func<Task> After { get; set; }
public AsyncToCoroutine(bool cleanup = true)
{
m_Context = new CoroutineSynchronizationContext();
m_Cleanup = cleanup;
}
public IEnumerator Run(Func<Task> func)
{
return Run(func, null);
}
// This method exists so we can avoid getting compiler warnings
// from non-async tests even if their Before/After are async
public IEnumerator Run(Action action)
{
return Run(null, action);
}
IEnumerator Run(Func<Task> func, Action action)
{
var oldContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(m_Context);
var task = RunAll();
while (!task.IsCompleted)
{
// Run any code that''s queued up.
m_Context.Exec();
// Skip frames until we're given more code or the task is done.
yield return null;
}
SynchronizationContext.SetSynchronizationContext(oldContext);
// Rethrow any exception that happened inside the task.
// Using a regular throw statement will lose the stack trace.
// https://stackoverflow.com/a/20170583
if (task.IsFaulted)
ExceptionDispatchInfo.Capture(task.Exception?.InnerException ?? task.Exception ?? new Exception("Unknown exception!")).Throw();
// Stupid hack to handle before/after methods that are async
// Ideally NUnit would do that for us but it doesn't support
// coroutines in it's Setup/Teardown methods.
async Task RunAll()
{
if (Before != null) await Before();
if (func != null)
await func();
else
action();
if (After != null) await After();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c1d51319285aaa429e2c9f02a3b031c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,35 @@
namespace Unity.Cloud.Collaborate.Tests
{
public class BasicTests : ScenarioTestBase
{
// [UnityTest]
// public IEnumerator AddedAssetsShowAsUntrackedChanges()
// {
// return atc.Run(async () =>
// {
//
// // ensure initial clean state.
// await EnsureCleanChangesPageInitially();
//
// // ensure file doesn't already exist.
// const string filename = "file1.txt";
// File.Exists(filename).ShouldBe(false, $"{filename} already exists");
//
// // todo - wrap operations like these in a dedicated helper class.
// File.WriteAllText(filename, "added file empty content .. ");
//
// // todo - ahmad : port the state monitoring implementation from
// // collab ver to here to avoid arbitrary UI wait times.
// await Task.Delay(1000);
//
// var entries = (await BackendProvider.Instance.GetChanges());
// entries.Count.ShouldBe(1, "changes count did not add file1");
// entries[0].Path.ShouldBe("file1.txt", "change added is not named file1.txt");
// entries[0].Status.ShouldBe(ChangeEntryStatus.Untracked, "change added is untracked");
//
// // clean up the file. (todo - ahmad) : this should be added in an after() method.
// File.Delete(filename);
// });
// }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b4ac8521087fe8f4d9328b06d9fcf387
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,56 @@
using System;
namespace Unity.Cloud.Collaborate.Tests
{
public class ScenarioTestBase
{
// protected AsyncToCoroutine atc;
//
// [SetUp]
// public void Setup()
// {
// atc = new AsyncToCoroutine();
// }
//
// [OneTimeSetUp]
// public void OneTimeSetup()
// {
// SourceControlGitImplementation.IsRunningTests = true;
// }
//
// [OneTimeTearDown]
// public void OneTimeTearDown()
// {
// SourceControlGitImplementation.IsRunningTests = false;
// }
//
// protected async Task EnsureCleanChangesPageInitially()
// {
// Threading.mainThreadId = Thread.CurrentThread.ManagedThreadId;
//
// if (!BackendProvider.Instance.IsProviderInstalled())
// {
// BackendProvider.Instance.InstallProvider();
// }
//
// // set git identity - using RyanC test dedicated account.
// BackendProvider.Instance.SetGitNameAndEmail("ryancas+collabtest", "ryancas+collabtest@unity3d.com");
//
// // ensure clean state , todo - ahmad : add this to a setup/teardown pair of methods.
// await BackendProvider.Instance.CreateRepository();
// await BackendProvider.Instance.InitializeClient();
//
// BackendProvider.Instance.DoesRepositoryExist().ShouldBe(true, "Repository is not initialized");
// BackendProvider.Instance.IsClientInitialized().ShouldBe(true, "Git is not initialized");
//
// BackendProvider.Instance.Start();
//
// // ensure clean state by publishing everything.
// await BackendProvider.Instance.Publish("initial publish");
//
// // assert clean state.
// (await BackendProvider.Instance.GetChanges()).Count.ShouldBe(0, "file change count is not zero");
// }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38f16807aeb0a5349920644eef3e04f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,9 @@
using System;
namespace Unity.Cloud.Collaborate.Tests
{
public static class TestConstants
{
public const int RENDER_UI_THREAD_DELAY = 1000;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a374bf192ac57b94e9082ff6e1debb2a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,59 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
namespace Unity.Cloud.Collaborate.Tests
{
public static class TestHelpers
{
public const string TestDirectory = "SomePathName/";
static readonly TaskFactory k_MyTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return k_MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func<Task> func)
{
k_MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static void ThrowsAsync<T>(Func<Task> asyncDelegate) where T : Exception
{
Assert.Throws<T>(() => RunSync(asyncDelegate));
}
public static void ShouldBe<T>(this T expr1, T value, string msg = "")
{
if (!expr1.Equals(value))
throw new InvalidOperationException($"Test expected {value}, but found : {expr1}. [{msg}]");
}
public static void ShouldBe(this object expr1, object value, string msg = "")
{
if (expr1 != value)
throw new InvalidOperationException($"Test expected {value}, but found : {expr1}. [{msg}]");
}
public static void ShouldBeNull(object obj, string msg = "")
{
if (obj != null)
throw new InvalidOperationException($"Test expected null value, but found : {obj}. [{msg}]" );
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f922ccdce989b741a2eb502779aca3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
using System;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Tests
{
internal class TestWindow : EditorWindow
{
void OnEnable()
{
var root = rootVisualElement;
root.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(CollaborateWindow.MainStylePath));
root.AddToClassList(EditorGUIUtility.isProSkin
? UiConstants.ussDark
: UiConstants.ussLight);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c3d6675532299974b9b16a1b9dcbab2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,141 @@
// This code snippet was provided originally by stanislav.osipov@unity3d.com from #ui-elements slack channel.
using System;
using System.Collections;
using Unity.Cloud.Collaborate.Assets;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Tests
{
internal static class UiTestHelpers
{
#region Events
// In order for tests to run without an EditorWindow but still be able to send
// events, we sometimes need to force the event type. IMGUI::GetEventType() (native) will
// return the event type as Ignore if the proper views haven't yet been
// initialized. This (falsely) breaks tests that rely on the event type. So for tests, we
// just ensure the event type is what we originally set it to when we sent it.
// This original type can be retrieved via Event.rawType.
static Event CreateEvent(Event evt)
{
return evt; //UIElementsUtility.CreateEvent(evt, evt.rawType);
}
public static Event MakeEvent(EventType type)
{
var evt = new Event { type = type };
return CreateEvent(evt);
}
public static Event MakeEvent(EventType type, Vector2 position)
{
var evt = new Event { type = type, mousePosition = position };
return CreateEvent(evt);
}
public static Event MakeKeyEvent(KeyCode code, EventType type = EventType.KeyDown, EventModifiers modifiers = EventModifiers.None, char character = '\0')
{
var evt = new Event { type = type, keyCode = code, character = character, modifiers = modifiers };
return CreateEvent(evt);
}
public static Event MakeMouseEvent(EventType type, Vector2 position, MouseButton button = MouseButton.LeftMouse, EventModifiers modifiers = EventModifiers.None, int clickCount = 1)
{
var evt = new Event { type = type, mousePosition = position, button = (int)button, modifiers = modifiers, clickCount = clickCount };
return CreateEvent(evt);
}
public static Event MakeScrollWheelEvent(Vector2 delta, Vector2 position)
{
var evt = new Event
{
type = EventType.ScrollWheel,
delta = delta,
mousePosition = position
};
return CreateEvent(evt);
}
public static Event MakeCommandEvent(EventType type, string command)
{
var evt = new Event { type = type, commandName = command };
return CreateEvent(evt);
}
#endregion
#region EditorWindow API
public static bool IsCompletelyVisible(EditorWindow window, VisualElement element)
{
if (element.ClassListContains(UiConstants.ussHidden))
{
return false;
}
var windowBounds = window.rootVisualElement.worldBound;
var elementBounds = element.worldBound;
return elementBounds.x >= windowBounds.x
&& elementBounds.y >= windowBounds.y
&& windowBounds.x + windowBounds.width >= elementBounds.x + elementBounds.width
&& windowBounds.y + windowBounds.height >= elementBounds.y + elementBounds.height;
}
public static bool IsPartiallyVisible(EditorWindow window, VisualElement element)
{
if (element.ClassListContains(UiConstants.ussHidden))
{
return false;
}
var windowBounds = window.rootVisualElement.worldBound;
var elementBounds = element.worldBound;
return !(elementBounds.x > windowBounds.x + windowBounds.width)
&& !(elementBounds.x + elementBounds.width < windowBounds.x)
&& !(elementBounds.y > windowBounds.y + windowBounds.height)
&& !(elementBounds.y + elementBounds.height < windowBounds.y);
}
public static void SendMouseDownEvent(EditorWindow window, VisualElement element)
{
var evt = MakeMouseEvent(EventType.MouseDown, element.worldBound.center);
window.SendEvent(evt);
}
public static void SendClickEvent(EditorWindow window, VisualElement element)
{
var evt = MakeMouseEvent(EventType.MouseDown, element.worldBound.center);
window.SendEvent(evt);
evt = MakeMouseEvent(EventType.MouseUp, element.worldBound.center);
window.SendEvent(evt);
}
public static void SimulateTyping(EditorWindow window, string text)
{
foreach (var character in text)
{
var evt = MakeKeyEvent(KeyCode.None, EventType.KeyDown, EventModifiers.None, character);
window.SendEvent(evt);
}
}
public static void SimulateTyping(EditorWindow window, char character, int repetitions)
{
for (var i = 0; i < repetitions; i++)
{
var evt = MakeKeyEvent(KeyCode.None, EventType.KeyDown, EventModifiers.None, character);
window.SendEvent(evt);
}
}
public static IEnumerator Pause(int frames)
{
for (var i = 0; i < frames; i++)
{
yield return null;
}
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d87a2d0d02b26be4db83375afe481d39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,23 @@
{
"name": "Unity.CollabProxy.EditorTests",
"references": [
"Unity.CollabProxy.Editor",
"UnityEngine.TestRunner",
"UnityEditor.TestRunner"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [],
"noEngineReferences": false
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 88c7566234a7f32409f05c32e6ae7b3e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,47 @@
# Unity Source Control Tests
This project contains the tests for the window/UI of this collab client.
## Overview
This is the structure of the project:
```none
<root>
├── .tests.json
└── Editor/
├── Unity.CollabProxy.EditorTests.asmdef
├── Components/
├── Models/
├── Ppresenters/
├── Scenario/
├── UserInterface/
└── Views/
```
Each directory features tests and mock classes for classes in the editor code.
## Tests
To run the tests, use the Unity Test Runner from within the Unity Editor. Unity Test Runner documentation is [here](https://docs.unity3d.com/Manual/testing-editortestsrunner.html).
## Adding a Test
While 100% coverage is hard to achieve, tests should be added with each new feature to ensure coverage either remains constant or increases.
With that out of the way, tests are in the typical C# format with a function with a `[Test]` decorator. Below is an example of a test taken from `Editor/Models/ChangesModelTests.cs`
```csharp
[Test]
public void ChangesModel_NullSourceControlEntries_EmptyResultLists()
{
var model = new TestableChangesModel();
model.UpdateChangeList(new List<IChangeEntry>());
var fullList = model.GetAllEntries();
Assert.AreEqual(1, fullList.Count);
Assert.IsTrue(fullList[0].All);
Assert.AreEqual(0, model.GetToggledEntries().Count);
Assert.AreEqual(0, model.GetUntoggledEntries().Count);
Assert.AreEqual(0, model.ToggledCount);
}
```
For documentation on the testing library, look at the NUnit [documentation](https://github.com/nunit/docs/wiki/NUnit-Documentation) over at GitHub. Unity Test Runner is a superset of NUnit and the documentation for that is [here](https://docs.unity3d.com/Manual/testing-editortestsrunner.html).
To access private/internal classes, creating a subclass and marking the parent fields as protected/internal will allow them to be used in testing.

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 41f2e51869a690f4bbd61bdf615f3e05
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: