PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/UnitTests/GitHub.App/ViewModels/RepositoryPublishViewModelTests.cs

https://gitlab.com/admin-github-cloud/VisualStudio
C# | 419 lines | 335 code | 84 blank | 0 comment | 5 complexity | bd86450c22ae325266d68a1eba43924d MD5 | raw file
  1. using System.Reactive.Linq;
  2. using GitHub.Models;
  3. using GitHub.Services;
  4. using GitHub.ViewModels;
  5. using NSubstitute;
  6. using Xunit;
  7. using UnitTests;
  8. using System.Threading.Tasks;
  9. using System;
  10. using GitHub.Primitives;
  11. using GitHub.Info;
  12. using System.Collections.Generic;
  13. using System.Collections.ObjectModel;
  14. using System.Linq;
  15. public class RepositoryPublishViewModelTests
  16. {
  17. public static class Helpers
  18. {
  19. public static IRepositoryPublishViewModel GetViewModel(IRepositoryPublishService service = null)
  20. {
  21. return GetViewModel(null, service, null);
  22. }
  23. public static IRepositoryPublishViewModel GetViewModel(
  24. IRepositoryHosts hosts = null,
  25. IRepositoryPublishService service = null,
  26. INotificationService notificationService = null,
  27. IConnectionManager connectionManager = null)
  28. {
  29. hosts = hosts ?? Substitutes.RepositoryHosts;
  30. service = service ?? Substitute.For<IRepositoryPublishService>();
  31. notificationService = notificationService ?? Substitute.For<INotificationService>();
  32. connectionManager = connectionManager ?? Substitutes.ConnectionManager;
  33. return new RepositoryPublishViewModel(hosts, service, notificationService, connectionManager,
  34. Substitute.For<IUsageTracker>());
  35. }
  36. public static void SetupConnections(IRepositoryHosts hosts, IConnectionManager cm,
  37. List<HostAddress> adds, List<IConnection> conns, List<IRepositoryHost> hsts,
  38. string uri)
  39. {
  40. var add = HostAddress.Create(new Uri(uri));
  41. var host = Substitute.For<IRepositoryHost>();
  42. var conn = Substitute.For<IConnection>();
  43. host.Address.Returns(add);
  44. conn.HostAddress.Returns(add);
  45. adds.Add(add);
  46. hsts.Add(host);
  47. conns.Add(conn);
  48. if (add.IsGitHubDotCom())
  49. hosts.GitHubHost.Returns(host);
  50. else
  51. hosts.EnterpriseHost.Returns(host);
  52. hosts.LookupHost(Arg.Is(add)).Returns(host);
  53. }
  54. public static IRepositoryPublishViewModel SetupConnectionsAndViewModel(
  55. IRepositoryHosts hosts = null,
  56. IRepositoryPublishService service = null,
  57. INotificationService notificationService = null,
  58. IConnectionManager cm = null,
  59. string uri = GitHubUrls.GitHub)
  60. {
  61. cm = cm ?? Substitutes.ConnectionManager;
  62. hosts = hosts ?? Substitute.For<IRepositoryHosts>();
  63. var adds = new List<HostAddress>();
  64. var hsts = new List<IRepositoryHost>();
  65. var conns = new List<IConnection>();
  66. SetupConnections(hosts, cm, adds, conns, hsts, uri);
  67. hsts[0].ModelService.GetAccounts().Returns(Observable.Return(new List<IAccount>()));
  68. cm.Connections.Returns(new ObservableCollection<IConnection>(conns));
  69. return GetViewModel(hosts, service, notificationService, cm);
  70. }
  71. public static string[] GetArgs(params string[] args)
  72. {
  73. var ret = new List<string>();
  74. foreach (var arg in args)
  75. if (arg != null)
  76. ret.Add(arg);
  77. return ret.ToArray();
  78. }
  79. }
  80. public class TheConnectionsProperty : TestBaseClass
  81. {
  82. [Theory]
  83. [InlineData(GitHubUrls.GitHub, "https://ghe.io" )]
  84. [InlineData("https://ghe.io", null)]
  85. [InlineData(GitHubUrls.GitHub, null)]
  86. public void ConnectionsMatchHosts(string arg1, string arg2)
  87. {
  88. var args = Helpers.GetArgs(arg1, arg2);
  89. var cm = Substitutes.ConnectionManager;
  90. var hosts = Substitute.For<IRepositoryHosts>();
  91. var adds = new List<HostAddress>();
  92. var hsts = new List<IRepositoryHost>();
  93. var conns = new List<IConnection>();
  94. foreach (var uri in args)
  95. Helpers.SetupConnections(hosts, cm, adds, conns, hsts, uri);
  96. foreach(var host in hsts)
  97. host.ModelService.GetAccounts().Returns(Observable.Return(new List<IAccount>()));
  98. cm.Connections.Returns(new ObservableCollection<IConnection>(conns));
  99. var vm = Helpers.GetViewModel(hosts: hosts, connectionManager: cm);
  100. var connections = vm.Connections;
  101. Assert.Equal(args.Length, connections.Count);
  102. for (int i = 0; i < conns.Count; i++)
  103. {
  104. Assert.Same(hsts[i], hosts.LookupHost(conns[i].HostAddress));
  105. }
  106. }
  107. }
  108. public class TheSelectedConnectionProperty : TestBaseClass
  109. {
  110. [Theory]
  111. [InlineData(GitHubUrls.GitHub, "https://ghe.io")]
  112. [InlineData("https://ghe.io", GitHubUrls.GitHub)]
  113. public void DefaultsToGitHub(string arg1, string arg2)
  114. {
  115. var args = Helpers.GetArgs(arg1, arg2);
  116. var cm = Substitutes.ConnectionManager;
  117. var hosts = Substitute.For<IRepositoryHosts>();
  118. var adds = new List<HostAddress>();
  119. var hsts = new List<IRepositoryHost>();
  120. var conns = new List<IConnection>();
  121. foreach (var uri in args)
  122. Helpers.SetupConnections(hosts, cm, adds, conns, hsts, uri);
  123. foreach (var host in hsts)
  124. host.ModelService.GetAccounts().Returns(Observable.Return(new List<IAccount>()));
  125. cm.Connections.Returns(new ObservableCollection<IConnection>(conns));
  126. var vm = Helpers.GetViewModel(hosts, connectionManager: cm);
  127. Assert.Same(adds.First(x => x.IsGitHubDotCom()), vm.SelectedConnection.HostAddress);
  128. Assert.Same(conns.First(x => x.HostAddress.IsGitHubDotCom()), vm.SelectedConnection);
  129. Assert.Same(hsts.First(x => x.Address.IsGitHubDotCom()), hosts.LookupHost(vm.SelectedConnection.HostAddress));
  130. }
  131. }
  132. public class TheAccountsProperty : TestBaseClass
  133. {
  134. [Fact]
  135. public void IsPopulatedByTheAccountsForTheSelectedHost()
  136. {
  137. var cm = Substitutes.ConnectionManager;
  138. var hosts = Substitute.For<IRepositoryHosts>();
  139. var adds = new List<HostAddress>();
  140. var hsts = new List<IRepositoryHost>();
  141. var conns = new List<IConnection>();
  142. Helpers.SetupConnections(hosts, cm, adds, conns, hsts, GitHubUrls.GitHub);
  143. Helpers.SetupConnections(hosts, cm, adds, conns, hsts, "https://ghe.io");
  144. var gitHubAccounts = new List<IAccount> { Substitute.For<IAccount>(), Substitute.For<IAccount>() };
  145. var enterpriseAccounts = new List<IAccount> { Substitute.For<IAccount>() };
  146. hsts.First(x => x.Address.IsGitHubDotCom()).ModelService.GetAccounts().Returns(Observable.Return(gitHubAccounts));
  147. hsts.First(x => !x.Address.IsGitHubDotCom()).ModelService.GetAccounts().Returns(Observable.Return(enterpriseAccounts));
  148. cm.Connections.Returns(new ObservableCollection<IConnection>(conns));
  149. var vm = Helpers.GetViewModel(hosts, connectionManager: cm);
  150. Assert.Equal(2, vm.Accounts.Count);
  151. Assert.Same(gitHubAccounts[0], vm.SelectedAccount);
  152. vm.SelectedConnection = conns.First(x => !x.HostAddress.IsGitHubDotCom());
  153. Assert.Equal(1, vm.Accounts.Count);
  154. Assert.Same(enterpriseAccounts[0], vm.SelectedAccount);
  155. }
  156. }
  157. public class TheSafeRepositoryNameProperty : TestBaseClass
  158. {
  159. [Fact]
  160. public void IsTheSameAsTheRepositoryNameWhenTheInputIsSafe()
  161. {
  162. var cm = Substitutes.ConnectionManager;
  163. var hosts = Substitute.For<IRepositoryHosts>();
  164. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  165. vm.RepositoryName = "this-is-bad";
  166. Assert.Equal(vm.RepositoryName, vm.SafeRepositoryName);
  167. }
  168. [Fact]
  169. public void IsConvertedWhenTheRepositoryNameIsNotSafe()
  170. {
  171. var cm = Substitutes.ConnectionManager;
  172. var hosts = Substitute.For<IRepositoryHosts>();
  173. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  174. vm.RepositoryName = "this is bad";
  175. Assert.Equal("this-is-bad", vm.SafeRepositoryName);
  176. }
  177. [Fact]
  178. public void IsNullWhenRepositoryNameIsNull()
  179. {
  180. var cm = Substitutes.ConnectionManager;
  181. var hosts = Substitute.For<IRepositoryHosts>();
  182. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  183. Assert.Null(vm.SafeRepositoryName);
  184. vm.RepositoryName = "not-null";
  185. vm.RepositoryName = null;
  186. Assert.Null(vm.SafeRepositoryName);
  187. }
  188. }
  189. public class TheRepositoryNameValidatorProperty : TestBaseClass
  190. {
  191. [Fact]
  192. public void IsFalseWhenRepoNameEmpty()
  193. {
  194. var cm = Substitutes.ConnectionManager;
  195. var hosts = Substitute.For<IRepositoryHosts>();
  196. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  197. vm.RepositoryName = "";
  198. Assert.False(vm.RepositoryNameValidator.ValidationResult.IsValid);
  199. Assert.Equal("Please enter a repository name", vm.RepositoryNameValidator.ValidationResult.Message);
  200. }
  201. [Fact]
  202. public void IsFalseWhenAfterBeingTrue()
  203. {
  204. var cm = Substitutes.ConnectionManager;
  205. var hosts = Substitute.For<IRepositoryHosts>();
  206. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  207. vm.RepositoryName = "repo";
  208. Assert.True(vm.PublishRepository.CanExecute(null));
  209. Assert.True(vm.RepositoryNameValidator.ValidationResult.IsValid);
  210. Assert.Empty(vm.RepositoryNameValidator.ValidationResult.Message);
  211. vm.RepositoryName = "";
  212. Assert.False(vm.RepositoryNameValidator.ValidationResult.IsValid);
  213. Assert.Equal("Please enter a repository name", vm.RepositoryNameValidator.ValidationResult.Message);
  214. }
  215. [Fact]
  216. public void IsTrueWhenRepositoryNameIsValid()
  217. {
  218. var cm = Substitutes.ConnectionManager;
  219. var hosts = Substitute.For<IRepositoryHosts>();
  220. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  221. vm.RepositoryName = "thisisfine";
  222. Assert.True(vm.RepositoryNameValidator.ValidationResult.IsValid);
  223. Assert.Empty(vm.RepositoryNameValidator.ValidationResult.Message);
  224. }
  225. }
  226. public class TheSafeRepositoryNameWarningValidatorProperty : TestBaseClass
  227. {
  228. [Fact]
  229. public void IsTrueWhenRepoNameIsSafe()
  230. {
  231. var cm = Substitutes.ConnectionManager;
  232. var hosts = Substitute.For<IRepositoryHosts>();
  233. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  234. vm.RepositoryName = "this-is-bad";
  235. Assert.True(vm.SafeRepositoryNameWarningValidator.ValidationResult.IsValid);
  236. }
  237. [Fact]
  238. public void IsFalseWhenRepoNameIsNotSafe()
  239. {
  240. var cm = Substitutes.ConnectionManager;
  241. var hosts = Substitute.For<IRepositoryHosts>();
  242. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  243. vm.RepositoryName = "this is bad";
  244. Assert.False(vm.SafeRepositoryNameWarningValidator.ValidationResult.IsValid);
  245. Assert.Equal("Will be created as this-is-bad", vm.SafeRepositoryNameWarningValidator.ValidationResult.Message);
  246. }
  247. [Fact]
  248. public void ResetsSafeNameValidator()
  249. {
  250. var cm = Substitutes.ConnectionManager;
  251. var hosts = Substitute.For<IRepositoryHosts>();
  252. var vm = Helpers.SetupConnectionsAndViewModel(hosts, cm: cm);
  253. vm.RepositoryName = "this";
  254. Assert.True(vm.SafeRepositoryNameWarningValidator.ValidationResult.IsValid);
  255. vm.RepositoryName = "this is bad";
  256. Assert.Equal("this-is-bad", vm.SafeRepositoryName);
  257. Assert.False(vm.SafeRepositoryNameWarningValidator.ValidationResult.IsValid);
  258. vm.RepositoryName = "this";
  259. Assert.True(vm.SafeRepositoryNameWarningValidator.ValidationResult.IsValid);
  260. }
  261. }
  262. public class ThePublishRepositoryCommand : TestBaseClass
  263. {
  264. [Fact]
  265. public async Task RepositoryExistsCallsNotificationServiceWithError()
  266. {
  267. var cm = Substitutes.ConnectionManager;
  268. var hosts = Substitute.For<IRepositoryHosts>();
  269. var notificationService = Substitute.For<INotificationService>();
  270. var repositoryPublishService = Substitute.For<IRepositoryPublishService>();
  271. repositoryPublishService.PublishRepository(Args.NewRepository, Args.Account, Args.ApiClient)
  272. .Returns(Observable.Throw<Octokit.Repository>(new Octokit.RepositoryExistsException("repo-name", new Octokit.ApiValidationException())));
  273. var vm = Helpers.SetupConnectionsAndViewModel(hosts, repositoryPublishService, notificationService, cm);
  274. vm.RepositoryName = "repo-name";
  275. await vm.PublishRepository.ExecuteAsync().Catch(Observable.Return(ProgressState.Fail));
  276. Assert.NotNull(vm.SafeRepositoryNameWarningValidator.ValidationResult.Message);
  277. notificationService.DidNotReceive().ShowMessage(Args.String);
  278. notificationService.Received().ShowError("There is already a repository named 'repo-name' for the current account.");
  279. }
  280. [Fact]
  281. public async Task ResetsWhenSwitchingHosts()
  282. {
  283. var args = Helpers.GetArgs(GitHubUrls.GitHub, "https://ghe.io");
  284. var cm = Substitutes.ConnectionManager;
  285. var hosts = Substitute.For<IRepositoryHosts>();
  286. var adds = new List<HostAddress>();
  287. var hsts = new List<IRepositoryHost>();
  288. var conns = new List<IConnection>();
  289. foreach (var uri in args)
  290. Helpers.SetupConnections(hosts, cm, adds, conns, hsts, uri);
  291. foreach (var host in hsts)
  292. host.ModelService.GetAccounts().Returns(Observable.Return(new List<IAccount>()));
  293. cm.Connections.Returns(new ObservableCollection<IConnection>(conns));
  294. var notificationService = Substitute.For<INotificationService>();
  295. var repositoryPublishService = Substitute.For<IRepositoryPublishService>();
  296. repositoryPublishService.PublishRepository(Args.NewRepository, Args.Account, Args.ApiClient)
  297. .Returns(Observable.Throw<Octokit.Repository>(new Octokit.RepositoryExistsException("repo-name", new Octokit.ApiValidationException())));
  298. var vm = Helpers.GetViewModel(hosts, repositoryPublishService, notificationService, cm);
  299. vm.RepositoryName = "repo-name";
  300. await vm.PublishRepository.ExecuteAsync().Catch(Observable.Return(ProgressState.Fail));
  301. Assert.Equal("repo-name", vm.RepositoryName);
  302. notificationService.Received().ShowError("There is already a repository named 'repo-name' for the current account.");
  303. var wasCalled = false;
  304. vm.SafeRepositoryNameWarningValidator.PropertyChanged += (s, e) => wasCalled = true;
  305. vm.SelectedConnection = conns.First(x => x != vm.SelectedConnection);
  306. Assert.True(wasCalled);
  307. }
  308. [Fact]
  309. public async Task ResetsWhenSwitchingAccounts()
  310. {
  311. var cm = Substitutes.ConnectionManager;
  312. var hosts = Substitute.For<IRepositoryHosts>();
  313. var adds = new List<HostAddress>();
  314. var hsts = new List<IRepositoryHost>();
  315. var conns = new List<IConnection>();
  316. Helpers.SetupConnections(hosts, cm, adds, conns, hsts, GitHubUrls.GitHub);
  317. var accounts = new List<IAccount> { Substitute.For<IAccount>(), Substitute.For<IAccount>() };
  318. hsts[0].ModelService.GetAccounts().Returns(Observable.Return(accounts));
  319. cm.Connections.Returns(new ObservableCollection<IConnection>(conns));
  320. var notificationService = Substitute.For<INotificationService>();
  321. var repositoryPublishService = Substitute.For<IRepositoryPublishService>();
  322. repositoryPublishService.PublishRepository(Args.NewRepository, Args.Account, Args.ApiClient)
  323. .Returns(Observable.Throw<Octokit.Repository>(new Octokit.RepositoryExistsException("repo-name", new Octokit.ApiValidationException())));
  324. var vm = Helpers.GetViewModel(hosts, repositoryPublishService, notificationService, cm);
  325. vm.RepositoryName = "repo-name";
  326. await vm.PublishRepository.ExecuteAsync().Catch(Observable.Return(ProgressState.Fail));
  327. Assert.Equal("repo-name", vm.RepositoryName);
  328. notificationService.Received().ShowError("There is already a repository named 'repo-name' for the current account.");
  329. var wasCalled = false;
  330. vm.SafeRepositoryNameWarningValidator.PropertyChanged += (s, e) => wasCalled = true;
  331. vm.SelectedAccount = accounts[1];
  332. Assert.True(wasCalled);
  333. }
  334. }
  335. }