public static MocksRepository ResolveRepository(UnresolvedContextBehavior unresolvedContextBehavior)
		{
			var stackTrace = new StackTrace();

			MethodBase callingMethodOutsideJustmock = null;
			foreach (var method in stackTrace.EnumerateFrames())
			{
				if (contextMethod == method)
					return contextRepository;

				if (callingMethodOutsideJustmock == null && method.Module.Assembly != typeof(MocksRepository).Assembly)
					callingMethodOutsideJustmock = method;
			}

			if (callingMethodOutsideJustmock != null && unresolvedContextBehavior == UnresolvedContextBehavior.CreateNewContextualOrLocal)
			{
				// don't reset the old repository - because the mocks created from it may still be used, e.g. if the method
				// associated with ResolveRepository works as a factory for mocks which are then exercised elsewhere
				contextMethod = callingMethodOutsideJustmock;
				contextRepository = new MocksRepository(null, contextMethod);

				return contextRepository;
			}

			return null;
		}
		public static void RetireRepository()
		{
			var stackTrace = new StackTrace();

			if (stackTrace.EnumerateFrames().Contains(contextMethod))
			{
				contextRepository.Retire();
				
				contextMethod = null;
				contextRepository = null;
			}
		}
		public override bool RetireRepository()
		{
			var stackTrace = new StackTrace();
			var testMethod = FindExistingTestMethod(stackTrace.EnumerateFrames());

			if (testMethod == null)
				return false;

			var key = testMethod.DeclaringType;
			var repo = repositories[key];
			repositories.Remove(key);
			repo.Retire();

			return true;
		}
		public override MocksRepository ResolveRepository(UnresolvedContextBehavior unresolvedContextBehavior)
		{
			var stackTrace = new StackTrace();
			var frames = stackTrace.EnumerateFrames().ToList();
			var testMethod = FindExistingTestMethod(frames);
			if (testMethod != null)
				return repositories[testMethod.DeclaringType];
			if (unresolvedContextBehavior == UnresolvedContextBehavior.DoNotCreateNew)
				return null;

			var caller = frames.FirstOrDefault(method => method.Module.Assembly != typeof(MocksRepository).Assembly);
			var mspecTestClass = caller.DeclaringType;

			MocksRepository parentRepo;
			repositories.TryGetValue(mspecTestClass.BaseType, out parentRepo);

			var repo = new MocksRepository(parentRepo, caller);
			repositories.Add(mspecTestClass, repo);

			return repo;
		}
		public void Process(Invocation invocation)
		{
			if (invocation.IsReturnValueSet)
				return;

			var returnType = invocation.Method.GetReturnType();
			if (returnType == typeof(void) || returnType.IsValueType)
				return;

			if (invocation.Method.Name == "ToString" && invocation.Method.GetParameters().Length == 0 && invocation.UserProvidedImplementation)
				return;

			object mock = null;
			List<KeyValuePair<object, object>> mocksList;
			if (mocks.TryGetValue(invocation.Method, out mocksList))
			{
				// can't put the key part in a Dictionary,
				// because we can't be sure that GetHashCode() works
				mock = mocksList.FirstOrDefault(kvp => Equals(kvp.Key, invocation.Instance)).Value;
			}

			if (mock == null)
			{
				var parentMock = MocksRepository.GetMockMixinFromInvocation(invocation);
				var repository = parentMock.Repository;
				var replicator = parentMock as IMockReplicator;

				bool mustReturnAMock = invocation.InArrange || this.type == RecursiveMockingBehaviorType.ReturnMock;
				if (mustReturnAMock || this.type == RecursiveMockingBehaviorType.ReturnDefault)
				{
					if (returnType.IsArray)
					{
						mock = Array.CreateInstance(returnType.GetElementType(), Enumerable.Repeat(0, returnType.GetArrayRank()).ToArray());
					}

					var idictionaryType = returnType.GetImplementationOfGenericInterface(typeof(IDictionary<,>));
					if (mock == null && idictionaryType != null)
					{
						var dictType = typeof(Dictionary<,>).MakeGenericType(idictionaryType.GetGenericArguments());
						mock = MockCollection.Create(returnType, repository, replicator, (IEnumerable)MockingUtil.CreateInstance(dictType));
					}

					var ienumerableType = returnType.GetImplementationOfGenericInterface(typeof(IEnumerable<>));
					if (mock == null && ienumerableType != null)
					{
						var listType = typeof(List<>).MakeGenericType(ienumerableType.GetGenericArguments());
						mock = MockCollection.Create(returnType, repository, replicator, (IEnumerable)MockingUtil.CreateInstance(listType));
					}

					if (mock == null && mustReturnAMock)
					{
#if !LITE_EDITION
						var stackTrace = new StackTrace();
						var methodCallingArrange = stackTrace.EnumerateFrames()
							.SkipWhile(m => !Attribute.IsDefined(m, typeof(ArrangeMethodAttribute)))
							.SkipWhile(m => m.Module.Assembly == typeof(MocksRepository).Assembly)
							.FirstOrDefault();

						if (methodCallingArrange != null && invocation.Method.DeclaringType.IsAssignableFrom(methodCallingArrange.DeclaringType))
							return;
#endif

						if (typeof(String) == returnType)
						{
							mock = String.Empty;
						}
						else
						{
							try
							{
								mock = replicator.CreateSimilarMock(repository, returnType, null, true, null);
							}
							catch (MockException)
							{ }
						}
					}
				}

				if (mock == null)
					return;

				if (mocksList == null)
				{
					mocksList = new List<KeyValuePair<object, object>>();
					mocks.Add(invocation.Method, mocksList);
				}
				mocksList.Add(new KeyValuePair<object, object>(invocation.Instance, mock));

				var mockMixin = MocksRepository.GetMockMixin(mock, null);
				if (parentMock != null && mockMixin != null)
					parentMock.DependentMocks.Add(mock);
			}

			invocation.ReturnValue = mock;
			invocation.CallOriginal = false;
			invocation.UserProvidedImplementation = true;
		}
		private MethodBase FindTestMethod(out int repoIdx, out RepositoryOperationsBase entryOps)
		{
			var stackTrace = new StackTrace();
			var q = from method in stackTrace.EnumerateFrames()
					where repoOperations.Any(repo => repo.MatchesMethod(method))
					select method;
			var testMethod = q.FirstOrDefault();
			if (testMethod != null)
			{
				var disableAttr = Attribute.GetCustomAttribute(testMethod, typeof(DisableAutomaticRepositoryResetAttribute)) as DisableAutomaticRepositoryResetAttribute;
				if (disableAttr != null
					&& ProfilerInterceptor.IsProfilerAttached
					&& !disableAttr.AllowMocking)
					throw new MockException("Using the mocking API in a test method decorated with DisableAutomaticRepositoryResetAttribute is unsafe. Read the documentation of the DisableAutomaticRepositoryResetAttribute class for further information and possible solutions.");
			}

			repoIdx = 0;
			entryOps = null;
			if (testMethod != null)
			{
				for (repoIdx = 0; repoIdx < this.repoOperations.Count; ++repoIdx)
				{
					var ops = this.repoOperations[repoIdx];
					if (ops.MatchesMethod(testMethod))
					{
						entryOps = ops;
						break;
					}
				}

				Debug.Assert(entryOps != null);
			}

			return testMethod;
		}
		private MethodBase FindTestMethod(out int repoIdx, out RepositoryOperationsBase entryOps)
		{
			var stackTrace = new StackTrace();
			var q = from method in stackTrace.EnumerateFrames()
					where repoOperations.Any(repo => repo.MatchesMethod(method))
					select method;

			var allTestMethods = q.Distinct().ToArray();
			if (allTestMethods.Length > 1)
			{
				var message = "Calling one test method from another could result in unexpected behavior and must be avoided. Extract common mocking logic to a non-test method. At:\n" + stackTrace;
				DebugView.DebugTrace(message);
			}
			var testMethod = allTestMethods.FirstOrDefault();

			if (testMethod != null)
			{
				var disableAttr = Attribute.GetCustomAttribute(testMethod, typeof(DisableAutomaticRepositoryResetAttribute)) as DisableAutomaticRepositoryResetAttribute;
				if (disableAttr != null
					&& ProfilerInterceptor.IsProfilerAttached
					&& !disableAttr.AllowMocking)
					throw new MockException("Using the mocking API in a test method decorated with DisableAutomaticRepositoryResetAttribute is unsafe. Read the documentation of the DisableAutomaticRepositoryResetAttribute class for further information and possible solutions.");
			}

			repoIdx = 0;
			entryOps = null;
			if (testMethod != null)
			{
				for (repoIdx = 0; repoIdx < this.repoOperations.Count; ++repoIdx)
				{
					var ops = this.repoOperations[repoIdx];
					if (ops.MatchesMethod(testMethod))
					{
						entryOps = ops;
						break;
					}
				}

				Debug.Assert(entryOps != null);
			}

			return testMethod;
		}
		private bool MustReturnMock(Invocation invocation, bool checkPropertyOnTestFixture = false)
		{
			if (checkPropertyOnTestFixture)
			{
#if !LITE_EDITION
				var stackTrace = new StackTrace();
				var methodCallingArrange = stackTrace.EnumerateFrames()
					.SkipWhile(m => !Attribute.IsDefined(m, typeof(ArrangeMethodAttribute)))
					.SkipWhile(m => m.Module.Assembly == typeof(MocksRepository).Assembly)
					.FirstOrDefault();

				if (methodCallingArrange != null && invocation.Method.DeclaringType.IsAssignableFrom(methodCallingArrange.DeclaringType))
					return false;
#endif
			}

			return invocation.InArrange || this.type == RecursiveMockingBehaviorType.ReturnMock;
		}
		public void Process(Invocation invocation)
		{
			if (invocation.ReturnValue != null)
				return;

			var returnType = invocation.Method.GetReturnType();
			if (returnType == typeof(void) || returnType.IsValueType)
				return;

			var key = new KeyValuePair<object, MethodBase>(invocation.Instance, invocation.Method);
			object mock;
			if (!mocks.TryGetValue(key, out mock))
			{
				var parentMock = MocksRepository.GetMockMixinFromInvocation(invocation);
				var repository = parentMock.Repository;
				var replicator = parentMock as IMockReplicator;

				bool mustReturnAMock = invocation.InArrange || this.type == RecursiveMockingBehaviorType.ReturnMock;
				if (mustReturnAMock || this.type == RecursiveMockingBehaviorType.ReturnDefault)
				{
					if (returnType.IsArray)
					{
						mock = Array.CreateInstance(returnType.GetElementType(), Enumerable.Repeat(0, returnType.GetArrayRank()).ToArray());
					}

					var idictionaryType = returnType.GetImplementationOfGenericInterface(typeof(IDictionary<,>));
					if (mock == null && idictionaryType != null)
					{
						var dictType = typeof(Dictionary<,>).MakeGenericType(idictionaryType.GetGenericArguments());
						mock = MockCollection.Create(returnType, repository, replicator, (IEnumerable)MockingUtil.CreateInstance(dictType));
					}

					var ienumerableType = returnType.GetImplementationOfGenericInterface(typeof(IEnumerable<>));
					if (mock == null && ienumerableType != null)
					{
						var listType = typeof(List<>).MakeGenericType(ienumerableType.GetGenericArguments());
						mock = MockCollection.Create(returnType, repository, replicator, (IEnumerable)MockingUtil.CreateInstance(listType));
					}

					if (mock == null && mustReturnAMock)
					{
						var stackTrace = new StackTrace();
						var methodCallingArrange = stackTrace.EnumerateFrames()
							.SkipWhile(m => !Attribute.IsDefined(m, typeof(ArrangeMethodAttribute)))
							.SkipWhile(m => m.Module.Assembly == typeof(MocksRepository).Assembly)
							.FirstOrDefault();

						if (methodCallingArrange != null && invocation.Method.DeclaringType.IsAssignableFrom(methodCallingArrange.DeclaringType))
							return;

						if (typeof(String) == returnType)
						{
							mock = String.Empty;
						}
						else
						{
							try
							{
								mock = replicator.CreateSimilarMock(repository, returnType, null, true, null);
							}
							catch (MockException ex)
							{ }
						}
					}
				}

				if (mock == null)
					return;
				
				mocks.Add(key, mock);

				var mockMixin = MocksRepository.GetMockMixin(mock, null);
				if (parentMock != null && mockMixin != null)
					parentMock.DependentMocks.Add(mock);
			}

			invocation.ReturnValue = mock;
			invocation.CallOriginal = false;
			invocation.UserProvidedImplementation = true;
		}