PageRenderTime 35ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/test/System.Web.Mvc.Test/Test/DefaultControllerFactoryTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 766 lines | 548 code | 123 blank | 95 comment | 0 complexity | 3965fd179eb80beff49e1e28eb5b7a69 MD5 | raw file
  1. using System.Reflection;
  2. using System.Web.Routing;
  3. using System.Web.SessionState;
  4. using Moq;
  5. using Xunit;
  6. using Xunit.Extensions;
  7. using Assert = Microsoft.TestCommon.AssertEx;
  8. namespace System.Web.Mvc.Test
  9. {
  10. [CLSCompliant(false)]
  11. public class DefaultControllerFactoryTest
  12. {
  13. static DefaultControllerFactoryTest()
  14. {
  15. MvcTestHelper.CreateMvcAssemblies();
  16. }
  17. [Fact]
  18. public void CreateAmbiguousControllerException_RouteWithoutUrl()
  19. {
  20. // Arrange
  21. RouteBase route = new Mock<RouteBase>().Object;
  22. Type[] matchingTypes = new Type[]
  23. {
  24. typeof(object),
  25. typeof(string)
  26. };
  27. // Act
  28. InvalidOperationException exception = DefaultControllerFactory.CreateAmbiguousControllerException(route, "Foo", matchingTypes);
  29. // Assert
  30. Assert.Equal(@"Multiple types were found that match the controller named 'Foo'. This can happen if the route that services this request does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
  31. The request for 'Foo' has found the following matching controllers:
  32. System.Object
  33. System.String", exception.Message);
  34. }
  35. [Fact]
  36. public void CreateAmbiguousControllerException_RouteWithUrl()
  37. {
  38. // Arrange
  39. RouteBase route = new Route("{controller}/blah", new Mock<IRouteHandler>().Object);
  40. Type[] matchingTypes = new Type[]
  41. {
  42. typeof(object),
  43. typeof(string)
  44. };
  45. // Act
  46. InvalidOperationException exception = DefaultControllerFactory.CreateAmbiguousControllerException(route, "Foo", matchingTypes);
  47. // Assert
  48. Assert.Equal(@"Multiple types were found that match the controller named 'Foo'. This can happen if the route that services this request ('{controller}/blah') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
  49. The request for 'Foo' has found the following matching controllers:
  50. System.Object
  51. System.String", exception.Message);
  52. }
  53. [Fact]
  54. public void CreateControllerWithNullContextThrows()
  55. {
  56. // Arrange
  57. DefaultControllerFactory factory = new DefaultControllerFactory();
  58. // Act
  59. Assert.ThrowsArgumentNull(
  60. delegate
  61. {
  62. ((IControllerFactory)factory).CreateController(
  63. null,
  64. "foo");
  65. },
  66. "requestContext");
  67. }
  68. [Fact]
  69. public void CreateControllerWithEmptyControllerNameThrows()
  70. {
  71. // Arrange
  72. DefaultControllerFactory factory = new DefaultControllerFactory();
  73. // Act
  74. Assert.Throws<ArgumentException>(
  75. delegate
  76. {
  77. ((IControllerFactory)factory).CreateController(
  78. new RequestContext(new Mock<HttpContextBase>().Object, new RouteData()),
  79. String.Empty);
  80. },
  81. "Value cannot be null or empty.\r\nParameter name: controllerName");
  82. }
  83. [Fact]
  84. public void CreateControllerReturnsControllerInstance()
  85. {
  86. // Arrange
  87. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  88. Mock<DefaultControllerFactory> factoryMock = new Mock<DefaultControllerFactory>();
  89. factoryMock.CallBase = true;
  90. factoryMock.Setup(o => o.GetControllerType(requestContext, "moo")).Returns(typeof(DummyController));
  91. // Act
  92. IController controller = ((IControllerFactory)factoryMock.Object).CreateController(requestContext, "moo");
  93. // Assert
  94. Assert.IsType<DummyController>(controller);
  95. }
  96. [Fact]
  97. public void CreateControllerCanReturnNull()
  98. {
  99. // Arrange
  100. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  101. Mock<DefaultControllerFactory> factoryMock = new Mock<DefaultControllerFactory>();
  102. factoryMock.Setup(o => o.GetControllerType(requestContext, "moo")).Returns(typeof(DummyController));
  103. factoryMock.Setup(o => o.GetControllerInstance(requestContext, typeof(DummyController))).Returns((ControllerBase)null);
  104. // Act
  105. IController controller = ((IControllerFactory)factoryMock.Object).CreateController(requestContext, "moo");
  106. // Assert
  107. Assert.Null(controller);
  108. }
  109. [Fact]
  110. public void DisposeControllerFactoryWithDisposableController()
  111. {
  112. // Arrange
  113. IControllerFactory factory = new DefaultControllerFactory();
  114. Mock<ControllerBase> mockController = new Mock<ControllerBase>();
  115. Mock<IDisposable> mockDisposable = mockController.As<IDisposable>();
  116. mockDisposable.Setup(d => d.Dispose()).Verifiable();
  117. // Act
  118. factory.ReleaseController(mockController.Object);
  119. // Assert
  120. mockDisposable.Verify();
  121. }
  122. [Fact]
  123. public void GetControllerInstanceThrowsIfControllerTypeIsNull()
  124. {
  125. // Arrange
  126. Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>();
  127. Mock<HttpRequestBase> requestMock = new Mock<HttpRequestBase>();
  128. contextMock.Setup(o => o.Request).Returns(requestMock.Object);
  129. requestMock.Setup(o => o.Path).Returns("somepath");
  130. RequestContext requestContext = new RequestContext(contextMock.Object, new RouteData());
  131. Mock<DefaultControllerFactory> factoryMock = new Mock<DefaultControllerFactory> { CallBase = true };
  132. factoryMock.Setup(o => o.GetControllerType(requestContext, "moo")).Returns((Type)null);
  133. // Act
  134. Assert.ThrowsHttpException(
  135. delegate { ((IControllerFactory)factoryMock.Object).CreateController(requestContext, "moo"); },
  136. "The controller for path 'somepath' was not found or does not implement IController.",
  137. 404);
  138. }
  139. [Fact]
  140. public void GetControllerInstanceThrowsIfControllerTypeIsNotControllerBase()
  141. {
  142. // Arrange
  143. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  144. DefaultControllerFactory factory = new DefaultControllerFactory();
  145. // Act
  146. Assert.Throws<ArgumentException>(
  147. delegate { factory.GetControllerInstance(requestContext, typeof(int)); },
  148. "The controller type 'System.Int32' must implement IController.\r\nParameter name: controllerType");
  149. }
  150. [Fact]
  151. public void GetControllerInstanceWithBadConstructorThrows()
  152. {
  153. // Arrange
  154. Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>();
  155. RequestContext requestContext = new RequestContext(contextMock.Object, new RouteData());
  156. Mock<DefaultControllerFactory> factoryMock = new Mock<DefaultControllerFactory>();
  157. factoryMock.CallBase = true;
  158. factoryMock.Setup(o => o.GetControllerType(requestContext, "moo")).Returns(typeof(DummyControllerThrows));
  159. // Act
  160. Exception ex = Assert.Throws<InvalidOperationException>(
  161. delegate { ((IControllerFactory)factoryMock.Object).CreateController(requestContext, "moo"); },
  162. "An error occurred when trying to create a controller of type 'System.Web.Mvc.Test.DefaultControllerFactoryTest+DummyControllerThrows'. Make sure that the controller has a parameterless public constructor.");
  163. Assert.Equal("constructor", ex.InnerException.InnerException.Message);
  164. }
  165. [Fact]
  166. public void GetControllerSessionBehaviorGuardClauses()
  167. {
  168. // Arrange
  169. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  170. IControllerFactory factory = new DefaultControllerFactory();
  171. // Act & Assert
  172. Assert.ThrowsArgumentNull(
  173. () => factory.GetControllerSessionBehavior(null, "controllerName"),
  174. "requestContext"
  175. );
  176. Assert.ThrowsArgumentNullOrEmpty(
  177. () => factory.GetControllerSessionBehavior(requestContext, null),
  178. "controllerName"
  179. );
  180. Assert.ThrowsArgumentNullOrEmpty(
  181. () => factory.GetControllerSessionBehavior(requestContext, ""),
  182. "controllerName"
  183. );
  184. }
  185. [Fact]
  186. public void GetControllerSessionBehaviorReturnsDefaultForNullControllerType()
  187. {
  188. // Arrange
  189. var factory = new DefaultControllerFactory();
  190. // Act
  191. SessionStateBehavior result = factory.GetControllerSessionBehavior(null, null);
  192. // Assert
  193. Assert.Equal(SessionStateBehavior.Default, result);
  194. }
  195. [Fact]
  196. public void GetControllerSessionBehaviorReturnsDefaultForControllerWithoutAttribute()
  197. {
  198. // Arrange
  199. var factory = new DefaultControllerFactory();
  200. // Act
  201. SessionStateBehavior result = factory.GetControllerSessionBehavior(null, typeof(object));
  202. // Assert
  203. Assert.Equal(SessionStateBehavior.Default, result);
  204. }
  205. [Fact]
  206. public void GetControllerSessionBehaviorReturnsAttributeValueFromController()
  207. {
  208. // Arrange
  209. var factory = new DefaultControllerFactory();
  210. // Act
  211. SessionStateBehavior result = factory.GetControllerSessionBehavior(null, typeof(MyReadOnlyController));
  212. // Assert
  213. Assert.Equal(SessionStateBehavior.ReadOnly, result);
  214. }
  215. [SessionState(SessionStateBehavior.ReadOnly)]
  216. class MyReadOnlyController
  217. {
  218. }
  219. [Fact]
  220. public void GetControllerTypeWithEmptyControllerNameThrows()
  221. {
  222. // Arrange
  223. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  224. DefaultControllerFactory factory = new DefaultControllerFactory();
  225. // Act
  226. Assert.Throws<ArgumentException>(
  227. delegate { factory.GetControllerType(requestContext, String.Empty); },
  228. "Value cannot be null or empty.\r\nParameter name: controllerName");
  229. }
  230. [Fact]
  231. public void GetControllerTypeForNoAssemblies()
  232. {
  233. // Arrange
  234. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  235. DefaultControllerFactory factory = new DefaultControllerFactory();
  236. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { });
  237. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  238. factory.BuildManager = buildManagerMock;
  239. factory.ControllerTypeCache = controllerTypeCache;
  240. // Act
  241. Type controllerType = factory.GetControllerType(requestContext, "sometype");
  242. // Assert
  243. Assert.Null(controllerType);
  244. Assert.Equal(0, controllerTypeCache.Count);
  245. }
  246. [Fact]
  247. public void GetControllerTypeForOneAssembly()
  248. {
  249. // Arrange
  250. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  251. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns2a.ns2b");
  252. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1") });
  253. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  254. factory.BuildManager = buildManagerMock;
  255. factory.ControllerTypeCache = controllerTypeCache;
  256. // Act
  257. Type c1Type = factory.GetControllerType(requestContext, "C1");
  258. Type c2Type = factory.GetControllerType(requestContext, "c2");
  259. // Assert
  260. Assembly asm1 = Assembly.Load("MvcAssembly1");
  261. Type verifiedC1 = asm1.GetType("NS1a.NS1b.C1Controller");
  262. Type verifiedC2 = asm1.GetType("NS2a.NS2b.C2Controller");
  263. Assert.Equal(verifiedC1, c1Type);
  264. Assert.Equal(verifiedC2, c2Type);
  265. Assert.Equal(2, controllerTypeCache.Count);
  266. }
  267. [Fact]
  268. public void GetControllerTypeForManyAssemblies()
  269. {
  270. // Arrange
  271. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  272. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns2a.ns2b", "ns3a.ns3b", "ns4a.ns4b");
  273. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1"), Assembly.Load("MvcAssembly2") });
  274. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  275. factory.BuildManager = buildManagerMock;
  276. factory.ControllerTypeCache = controllerTypeCache;
  277. // Act
  278. Type c1Type = factory.GetControllerType(requestContext, "C1");
  279. Type c2Type = factory.GetControllerType(requestContext, "C2");
  280. Type c3Type = factory.GetControllerType(requestContext, "c3"); // lower case
  281. Type c4Type = factory.GetControllerType(requestContext, "c4"); // lower case
  282. // Assert
  283. Assembly asm1 = Assembly.Load("MvcAssembly1");
  284. Type verifiedC1 = asm1.GetType("NS1a.NS1b.C1Controller");
  285. Type verifiedC2 = asm1.GetType("NS2a.NS2b.C2Controller");
  286. Assembly asm2 = Assembly.Load("MvcAssembly2");
  287. Type verifiedC3 = asm2.GetType("NS3a.NS3b.C3Controller");
  288. Type verifiedC4 = asm2.GetType("NS4a.NS4b.C4Controller");
  289. Assert.NotNull(verifiedC1);
  290. Assert.NotNull(verifiedC2);
  291. Assert.NotNull(verifiedC3);
  292. Assert.NotNull(verifiedC4);
  293. Assert.Equal(verifiedC1, c1Type);
  294. Assert.Equal(verifiedC2, c2Type);
  295. Assert.Equal(verifiedC3, c3Type);
  296. Assert.Equal(verifiedC4, c4Type);
  297. Assert.Equal(4, controllerTypeCache.Count);
  298. }
  299. [Fact]
  300. public void GetControllerTypeDoesNotThrowIfSameControllerMatchedMultipleNamespaces()
  301. {
  302. // both namespaces "ns3a" and "ns3a.ns3b" will match a controller type, but it's actually
  303. // the same type. in this case, we shouldn't throw.
  304. // Arrange
  305. RequestContext requestContext = GetRequestContextWithNamespaces("ns3a", "ns3a.ns3b");
  306. requestContext.RouteData.DataTokens["UseNamespaceFallback"] = false;
  307. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns2a.ns2b");
  308. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly3") });
  309. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  310. factory.BuildManager = buildManagerMock;
  311. factory.ControllerTypeCache = controllerTypeCache;
  312. // Act
  313. Type c1Type = factory.GetControllerType(requestContext, "C1");
  314. // Assert
  315. Assembly asm3 = Assembly.Load("MvcAssembly3");
  316. Type verifiedC1 = asm3.GetType("NS3a.NS3b.C1Controller");
  317. Assert.NotNull(verifiedC1);
  318. Assert.Equal(verifiedC1, c1Type);
  319. }
  320. [Fact]
  321. public void GetControllerTypeForAssembliesWithSameTypeNamesInDifferentNamespaces()
  322. {
  323. // Arrange
  324. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  325. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns2a.ns2b");
  326. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1"), Assembly.Load("MvcAssembly3") });
  327. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  328. factory.BuildManager = buildManagerMock;
  329. factory.ControllerTypeCache = controllerTypeCache;
  330. // Act
  331. Type c1Type = factory.GetControllerType(requestContext, "C1");
  332. Type c2Type = factory.GetControllerType(requestContext, "C2");
  333. // Assert
  334. Assembly asm1 = Assembly.Load("MvcAssembly1");
  335. Type verifiedC1 = asm1.GetType("NS1a.NS1b.C1Controller");
  336. Type verifiedC2 = asm1.GetType("NS2a.NS2b.C2Controller");
  337. Assert.NotNull(verifiedC1);
  338. Assert.NotNull(verifiedC2);
  339. Assert.Equal(verifiedC1, c1Type);
  340. Assert.Equal(verifiedC2, c2Type);
  341. Assert.Equal(4, controllerTypeCache.Count);
  342. }
  343. [Fact]
  344. public void GetControllerTypeForAssembliesWithSameTypeNamesInDifferentNamespacesThrowsIfAmbiguous()
  345. {
  346. // Arrange
  347. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  348. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns3a.ns3b");
  349. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1"), Assembly.Load("MvcAssembly3") });
  350. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  351. factory.BuildManager = buildManagerMock;
  352. factory.ControllerTypeCache = controllerTypeCache;
  353. // Act
  354. Assert.Throws<InvalidOperationException>(
  355. delegate { factory.GetControllerType(requestContext, "C1"); },
  356. @"Multiple types were found that match the controller named 'C1'. This can happen if the route that services this request does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
  357. The request for 'C1' has found the following matching controllers:
  358. NS1a.NS1b.C1Controller
  359. NS3a.NS3b.C1Controller");
  360. // Assert
  361. Assert.Equal(4, controllerTypeCache.Count);
  362. }
  363. [Fact]
  364. public void GetControllerTypeForAssembliesWithSameTypeNamesInSameNamespaceThrows()
  365. {
  366. // Arrange
  367. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  368. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b");
  369. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1"), Assembly.Load("MvcAssembly4") });
  370. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  371. factory.BuildManager = buildManagerMock;
  372. factory.ControllerTypeCache = controllerTypeCache;
  373. // Act
  374. Assert.Throws<InvalidOperationException>(
  375. delegate { factory.GetControllerType(requestContext, "C1"); },
  376. @"Multiple types were found that match the controller named 'C1'. This can happen if the route that services this request does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
  377. The request for 'C1' has found the following matching controllers:
  378. NS1a.NS1b.C1Controller
  379. NS1a.NS1b.C1Controller");
  380. // Assert
  381. Assert.Equal(4, controllerTypeCache.Count);
  382. }
  383. [Fact]
  384. public void GetControllerTypeSearchesAllNamespacesAsLastResort()
  385. {
  386. // Arrange
  387. RequestContext requestContext = GetRequestContextWithNamespaces("ns3a.ns3b");
  388. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b");
  389. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1") });
  390. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  391. factory.BuildManager = buildManagerMock;
  392. factory.ControllerTypeCache = controllerTypeCache;
  393. // Act
  394. Type c2Type = factory.GetControllerType(requestContext, "C2");
  395. // Assert
  396. Assembly asm1 = Assembly.Load("MvcAssembly1");
  397. Type verifiedC2 = asm1.GetType("NS2a.NS2b.C2Controller");
  398. Assert.NotNull(verifiedC2);
  399. Assert.Equal(verifiedC2, c2Type);
  400. Assert.Equal(2, controllerTypeCache.Count);
  401. }
  402. [Fact]
  403. public void GetControllerTypeSearchesOnlyRouteDefinedNamespacesIfRequested()
  404. {
  405. // Arrange
  406. RequestContext requestContext = GetRequestContextWithNamespaces("ns3a.ns3b");
  407. requestContext.RouteData.DataTokens["UseNamespaceFallback"] = false;
  408. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns2a.ns2b");
  409. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1"), Assembly.Load("MvcAssembly3") });
  410. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  411. factory.BuildManager = buildManagerMock;
  412. factory.ControllerTypeCache = controllerTypeCache;
  413. // Act
  414. Type c1Type = factory.GetControllerType(requestContext, "C1");
  415. Type c2Type = factory.GetControllerType(requestContext, "C2");
  416. // Assert
  417. Assembly asm3 = Assembly.Load("MvcAssembly3");
  418. Type verifiedC1 = asm3.GetType("NS3a.NS3b.C1Controller");
  419. Assert.NotNull(verifiedC1);
  420. Assert.Equal(verifiedC1, c1Type);
  421. Assert.Null(c2Type);
  422. }
  423. [Fact]
  424. public void GetControllerTypeSearchesRouteDefinedNamespacesBeforeApplicationDefinedNamespaces()
  425. {
  426. // Arrange
  427. RequestContext requestContext = GetRequestContextWithNamespaces("ns3a.ns3b");
  428. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns2a.ns2b");
  429. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1"), Assembly.Load("MvcAssembly3") });
  430. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  431. factory.BuildManager = buildManagerMock;
  432. factory.ControllerTypeCache = controllerTypeCache;
  433. // Act
  434. Type c1Type = factory.GetControllerType(requestContext, "C1");
  435. Type c2Type = factory.GetControllerType(requestContext, "C2");
  436. // Assert
  437. Assembly asm1 = Assembly.Load("MvcAssembly1");
  438. Type verifiedC2 = asm1.GetType("NS2a.NS2b.C2Controller");
  439. Assembly asm3 = Assembly.Load("MvcAssembly3");
  440. Type verifiedC1 = asm3.GetType("NS3a.NS3b.C1Controller");
  441. Assert.NotNull(verifiedC1);
  442. Assert.NotNull(verifiedC2);
  443. Assert.Equal(verifiedC1, c1Type);
  444. Assert.Equal(verifiedC2, c2Type);
  445. Assert.Equal(4, controllerTypeCache.Count);
  446. }
  447. [Fact]
  448. public void GetControllerTypeThatDoesntExist()
  449. {
  450. // Arrange
  451. RequestContext requestContext = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
  452. DefaultControllerFactory factory = GetDefaultControllerFactory("ns1a.ns1b", "ns2a.ns2b", "ns3a.ns3b", "ns4a.ns4b");
  453. MockBuildManager buildManagerMock = new MockBuildManager(new Assembly[] { Assembly.Load("MvcAssembly1"), Assembly.Load("MvcAssembly2"), Assembly.Load("MvcAssembly3"), Assembly.Load("MvcAssembly4") });
  454. ControllerTypeCache controllerTypeCache = new ControllerTypeCache();
  455. factory.BuildManager = buildManagerMock;
  456. factory.ControllerTypeCache = controllerTypeCache;
  457. // Act
  458. Type randomType1 = factory.GetControllerType(requestContext, "Cx");
  459. Type randomType2 = factory.GetControllerType(requestContext, "Cy");
  460. Type randomType3 = factory.GetControllerType(requestContext, "Foo.Bar");
  461. Type randomType4 = factory.GetControllerType(requestContext, "C1Controller");
  462. // Assert
  463. Assert.Null(randomType1);
  464. Assert.Null(randomType2);
  465. Assert.Null(randomType3);
  466. Assert.Null(randomType4);
  467. Assert.Equal(8, controllerTypeCache.Count);
  468. }
  469. [Fact]
  470. public void IsControllerType()
  471. {
  472. // Act
  473. bool isController1 = ControllerTypeCache.IsControllerType(null);
  474. bool isController2 = ControllerTypeCache.IsControllerType(typeof(NonPublicController));
  475. bool isController3 = ControllerTypeCache.IsControllerType(typeof(MisspelledKontroller));
  476. bool isController4 = ControllerTypeCache.IsControllerType(typeof(AbstractController));
  477. bool isController5 = ControllerTypeCache.IsControllerType(typeof(NonIControllerController));
  478. bool isController6 = ControllerTypeCache.IsControllerType(typeof(Goodcontroller));
  479. // Assert
  480. Assert.False(isController1);
  481. Assert.False(isController2);
  482. Assert.False(isController3);
  483. Assert.False(isController4);
  484. Assert.False(isController5);
  485. Assert.True(isController6);
  486. }
  487. [Theory]
  488. [InlineData(null, false)]
  489. [InlineData("", true)]
  490. [InlineData("Dummy", false)]
  491. [InlineData("Dummy.*", true)]
  492. [InlineData("Dummy.Controller.*", false)]
  493. [InlineData("Dummy.Controllers", true)]
  494. [InlineData("Dummy.Controllers.*", true)]
  495. [InlineData("Dummy.Controllers*", false)]
  496. public void IsNamespaceMatch(string testNamespace, bool expectedResult)
  497. {
  498. // Act & Assert
  499. Assert.Equal(expectedResult, ControllerTypeCache.IsNamespaceMatch(testNamespace, "Dummy.Controllers"));
  500. }
  501. [Fact]
  502. public void GetControllerInstanceConsultsSetControllerActivator()
  503. {
  504. //Arrange
  505. Mock<IControllerActivator> activator = new Mock<IControllerActivator>();
  506. DefaultControllerFactory factory = new DefaultControllerFactory(activator.Object);
  507. RequestContext context = new RequestContext();
  508. //Act
  509. factory.GetControllerInstance(context, typeof(Goodcontroller));
  510. //Assert
  511. activator.Verify(l => l.Create(context, typeof(Goodcontroller)));
  512. }
  513. [Fact]
  514. public void GetControllerDelegatesToActivatorResolver()
  515. {
  516. //Arrange
  517. var context = new RequestContext();
  518. var expectedController = new Goodcontroller();
  519. var resolverActivator = new Mock<IControllerActivator>();
  520. resolverActivator.Setup(a => a.Create(context, typeof(Goodcontroller))).Returns(expectedController);
  521. var activatorResolver = new Resolver<IControllerActivator> { Current = resolverActivator.Object };
  522. var factory = new DefaultControllerFactory(null, activatorResolver, null);
  523. //Act
  524. IController returnedController = factory.GetControllerInstance(context, typeof(Goodcontroller));
  525. //Assert
  526. Assert.Same(returnedController, expectedController);
  527. }
  528. [Fact]
  529. public void GetControllerDelegatesToDependencyResolveWhenActivatorResolverIsNull()
  530. {
  531. // Arrange
  532. var context = new RequestContext();
  533. var expectedController = new Goodcontroller();
  534. var dependencyResolver = new Mock<IDependencyResolver>(MockBehavior.Strict);
  535. dependencyResolver.Setup(dr => dr.GetService(typeof(Goodcontroller))).Returns(expectedController);
  536. var factory = new DefaultControllerFactory(null, null, dependencyResolver.Object);
  537. // Act
  538. IController returnedController = factory.GetControllerInstance(context, typeof(Goodcontroller));
  539. // Assert
  540. Assert.Same(returnedController, expectedController);
  541. }
  542. [Fact]
  543. public void GetControllerDelegatesToActivatorCreateInstanceWhenDependencyResolverReturnsNull()
  544. {
  545. // Arrange
  546. var context = new RequestContext();
  547. var dependencyResolver = new Mock<IDependencyResolver>();
  548. var factory = new DefaultControllerFactory(null, null, dependencyResolver.Object);
  549. // Act & Assert
  550. Assert.Throws<InvalidOperationException>(
  551. () => factory.GetControllerInstance(context, typeof(NoParameterlessCtor)),
  552. "An error occurred when trying to create a controller of type 'System.Web.Mvc.Test.DefaultControllerFactoryTest+NoParameterlessCtor'. Make sure that the controller has a parameterless public constructor."
  553. );
  554. }
  555. [Fact]
  556. public void ActivatorResolverAndDependencyResolverAreNeverCalledWhenControllerActivatorIsPassedInConstructor()
  557. {
  558. // Arrange
  559. var context = new RequestContext();
  560. var expectedController = new Goodcontroller();
  561. Mock<IControllerActivator> activator = new Mock<IControllerActivator>();
  562. activator.Setup(a => a.Create(context, typeof(Goodcontroller))).Returns(expectedController);
  563. var resolverActivator = new Mock<IControllerActivator>(MockBehavior.Strict);
  564. var activatorResolver = new Resolver<IControllerActivator> { Current = resolverActivator.Object };
  565. var dependencyResolver = new Mock<IDependencyResolver>(MockBehavior.Strict);
  566. //Act
  567. var factory = new DefaultControllerFactory(activator.Object, activatorResolver, dependencyResolver.Object);
  568. IController returnedController = factory.GetControllerInstance(context, typeof(Goodcontroller));
  569. //Assert
  570. Assert.Same(returnedController, expectedController);
  571. }
  572. class NoParameterlessCtor : IController
  573. {
  574. public NoParameterlessCtor(int x)
  575. {
  576. }
  577. public void Execute(RequestContext requestContext)
  578. {
  579. }
  580. }
  581. private static DefaultControllerFactory GetDefaultControllerFactory(params string[] namespaces)
  582. {
  583. ControllerBuilder builder = new ControllerBuilder();
  584. builder.DefaultNamespaces.UnionWith(namespaces);
  585. return new DefaultControllerFactory() { ControllerBuilder = builder };
  586. }
  587. private static RequestContext GetRequestContextWithNamespaces(params string[] namespaces)
  588. {
  589. RouteData routeData = new RouteData();
  590. routeData.DataTokens["namespaces"] = namespaces;
  591. Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
  592. RequestContext requestContext = new RequestContext(mockHttpContext.Object, routeData);
  593. return requestContext;
  594. }
  595. private sealed class DummyController : ControllerBase
  596. {
  597. protected override void ExecuteCore()
  598. {
  599. throw new NotImplementedException();
  600. }
  601. }
  602. private sealed class DummyControllerThrows : IController
  603. {
  604. public DummyControllerThrows()
  605. {
  606. throw new Exception("constructor");
  607. }
  608. #region IController Members
  609. void IController.Execute(RequestContext requestContext)
  610. {
  611. throw new NotImplementedException();
  612. }
  613. #endregion
  614. }
  615. public interface IDisposableController : IController, IDisposable
  616. {
  617. }
  618. }
  619. // BAD: type isn't public
  620. internal class NonPublicController : Controller
  621. {
  622. }
  623. // BAD: type doesn't end with 'Controller'
  624. public class MisspelledKontroller : Controller
  625. {
  626. }
  627. // BAD: type is abstract
  628. public abstract class AbstractController : Controller
  629. {
  630. }
  631. // BAD: type doesn't implement IController
  632. public class NonIControllerController
  633. {
  634. }
  635. // GOOD: 'Controller' suffix should be case-insensitive
  636. public class Goodcontroller : Controller
  637. {
  638. }
  639. }