コード例 #1
0
        public void LoadTest(Type testType = null, Action onCompletion = null, bool isDynamicLoad = false)
        {
            if (CurrentTest?.Parent != null)
            {
                testContentContainer.Remove(CurrentTest.Parent);
                CurrentTest.Dispose();
            }

            var lastTest = CurrentTest;

            CurrentTest = null;

            if (testType == null && TestTypes.Count > 0)
            {
                testType = TestTypes[0];
            }

            config.Set(TestBrowserSetting.LastTest, testType?.Name ?? string.Empty);

            if (testType == null)
            {
                return;
            }

            var newTest = (TestScene)Activator.CreateInstance(testType);

            Debug.Assert(newTest != null);

            const string dynamic_prefix = "dynamic";

            // if we are a dynamically compiled type (via DynamicClassCompiler) we should update the dropdown accordingly.
            if (isDynamicLoad)
            {
                newTest.DynamicCompilationOriginal = lastTest?.DynamicCompilationOriginal ?? lastTest ?? newTest;
                toolbar.AddAssembly($"{dynamic_prefix} ({testType.Name})", testType.Assembly);
            }
            else
            {
                TestTypes.RemoveAll(t =>
                {
                    Debug.Assert(t.Assembly.FullName != null);
                    return(t.Assembly.FullName.Contains(dynamic_prefix));
                });

                newTest.DynamicCompilationOriginal = newTest;
            }

            Assembly.Value = testType.Assembly;

            CurrentTest = newTest;
            CurrentTest.OnLoadComplete += _ => Schedule(() => finishLoad(newTest, onCompletion));

            updateButtons();
            resetRecording();

            testContentContainer.Add(new ErrorCatchingDelayedLoadWrapper(CurrentTest, isDynamicLoad)
            {
                OnCaughtError = compileFailed
            });
        }
コード例 #2
0
            /// <summary>
            /// Blocks execution until a provided <see cref="TestScene"/> runs to completion.
            /// </summary>
            /// <param name="test">The <see cref="TestScene"/> to run.</param>
            public void RunTestBlocking(TestScene test)
            {
                Trace.Assert(host != null, $"Ensure this runner has been loaded before calling {nameof(RunTestBlocking)}");

                bool completed = false;
                ExceptionDispatchInfo exception = null;

                void complete()
                {
                    // We want to remove the TestScene from the hierarchy on completion as under nUnit, it may have operations run on it from a different thread.
                    // This is because nUnit will reuse the same class multiple times, running a different [Test] method each time, while the GameHost
                    // is run from its own asynchronous thread.
                    RemoveInternal(test);
                    completed = true;
                }

                Schedule(() =>
                {
                    AddInternal(test);

                    Console.WriteLine($@"{(int)Time.Current}: Running {test} visual test cases...");

                    // Nunit will run the tests in the TestScene with the same TestScene instance so the TestScene
                    // needs to be removed before the host is exited, otherwise it will end up disposed

                    test.RunAllSteps(() =>
                    {
                        Scheduler.AddDelayed(complete, time_between_tests);
                    }, e =>
                    {
                        if (e is DependencyInjectionException die)
                        {
                            exception = die.DispatchInfo;
                        }
                        else
                        {
                            exception = ExceptionDispatchInfo.Capture(e);
                        }
                        complete();
                    });
                });

                while (!completed && host.ExecutionState == ExecutionState.Running)
                {
                    Thread.Sleep(10);
                }

                exception?.Throw();
            }
コード例 #3
0
        private void onChange(object sender, FileSystemEventArgs e)
        {
            lock (compileLock)
            {
                if (checkpointObject == null || isCompiling)
                {
                    return;
                }

                var checkpointName = checkpointObject.GetType().Name;

                var reqTypes = checkpointObject.RequiredTypes.Select(t => removeGenerics(t.Name)).ToList();

                // add ourselves as a required type.
                reqTypes.Add(removeGenerics(checkpointName));
                // if we are a TestCase, add the class we are testing automatically.
                reqTypes.Add(TestScene.RemovePrefix(removeGenerics(checkpointName)));

                if (!reqTypes.Contains(Path.GetFileNameWithoutExtension(e.Name)))
                {
                    return;
                }

                if (!reqTypes.SequenceEqual(requiredTypeNames))
                {
                    requiredTypeNames = reqTypes;

                    requiredFiles.Clear();

                    foreach (var d in validDirectories)
                    {
                        requiredFiles.AddRange(Directory
                                               .EnumerateFiles(d, "*.cs", SearchOption.AllDirectories)
                                               .Where(fw => requiredTypeNames.Contains(Path.GetFileNameWithoutExtension(fw))));
                    }
                }

                lastTouchedFile = e.FullPath;

                isCompiling = true;
                Task.Run(recompile)
                .ContinueWith(_ => isCompiling = false);
            }
        }
コード例 #4
0
            public void RunTestBlocking(TestScene test)
            {
                Trace.Assert(host != null, $"Ensure this runner has been loaded before calling {nameof(RunTestBlocking)}");

                bool completed = false;
                ExceptionDispatchInfo exception = null;

                void complete()
                {
                    // We want to remove the TestScene from the hierarchy on completion as under nUnit, it may have operations run on it from a different thread.
                    // This is because nUnit will reuse the same class multiple times, running a different [Test] method each time, while the GameHost
                    // is run from its own asynchronous thread.
                    RemoveInternal(test);
                    completed = true;
                }

                Schedule(() =>
                {
                    AddInternal(test);

                    Logger.Log($@"💨 Class: {test.GetType().ReadableName()}");
                    Logger.Log($@"🔶 Test:  {TestContext.CurrentContext.Test.Name}");

                    // Nunit will run the tests in the TestScene with the same TestScene instance so the TestScene
                    // needs to be removed before the host is exited, otherwise it will end up disposed

                    test.RunAllSteps(() =>
                    {
                        Scheduler.AddDelayed(complete, time_between_tests);
                    }, e =>
                    {
                        exception = ExceptionDispatchInfo.Capture(e);
                        complete();
                    });
                });

                while (!completed && host.ExecutionState == ExecutionState.Running)
                {
                    Thread.Sleep(10);
                }

                exception?.Throw();
            }
コード例 #5
0
        private void updateList(ValueChangedEvent <Assembly> args)
        {
            leftFlowContainer.Clear();

            //Add buttons for each TestCase.
            string namespacePrefix = TestTypes.Select(t => t.Namespace).GetCommonPrefix();

            leftFlowContainer.AddRange(TestTypes.Where(t => t.Assembly == args.NewValue)
                                       .GroupBy(
                                           t =>
            {
                string group = t.Namespace?.Substring(namespacePrefix.Length).TrimStart('.');
                return(string.IsNullOrWhiteSpace(group) ? TestScene.RemovePrefix(t.Name) : group);
            },
                                           t => t,
                                           (group, types) => new TestGroup {
                Name = group, TestTypes = types.ToArray()
            }
                                           ).OrderBy(g => g.Name)
                                       .Select(t => new TestGroupButton(type => LoadTest(type), t)));
        }
コード例 #6
0
        public void LoadTest(Type testType = null, Action onCompletion = null, bool isDynamicLoad = false)
        {
            if (CurrentTest?.Parent != null)
            {
                testContentContainer.Remove(CurrentTest.Parent);
                CurrentTest.Dispose();
            }

            CurrentTest = null;

            if (testType == null && TestTypes.Count > 0)
            {
                testType = TestTypes[0];
            }

            config.SetValue(TestBrowserSetting.LastTest, testType?.FullName ?? string.Empty);

            if (testType == null)
            {
                return;
            }

            var newTest = (TestScene)Activator.CreateInstance(testType);

            Debug.Assert(newTest != null);

            Assembly.Value = testType.Assembly;

            CurrentTest = newTest;
            CurrentTest.OnLoadComplete += _ => Schedule(() => finishLoad(newTest, onCompletion));

            updateButtons();
            resetRecording();

            testContentContainer.Add(new ErrorCatchingDelayedLoadWrapper(CurrentTest, isDynamicLoad)
            {
                OnCaughtError = compileFailed
            });
        }
コード例 #7
0
        private void finishLoad(TestScene newTest, Action onCompletion)
        {
            if (CurrentTest != newTest)
            {
                // There could have been multiple loads fired after us. In such a case we want to silently remove ourselves.
                testContentContainer.Remove(newTest.Parent);
                return;
            }

            updateButtons();

            bool hadTestAttributeTest = false;

            foreach (var m in newTest.GetType().GetMethods())
            {
                var name = m.Name;

                if (name == nameof(TestScene.TestConstructor) || m.GetCustomAttribute(typeof(IgnoreAttribute), false) != null)
                {
                    continue;
                }

                if (name.StartsWith("Test"))
                {
                    name = name.Substring(4);
                }

                int runCount = 1;

                if (m.GetCustomAttribute(typeof(RepeatAttribute), false) != null)
                {
                    runCount += (int)m.GetCustomAttributesData().Single(a => a.AttributeType == typeof(RepeatAttribute)).ConstructorArguments.Single().Value;
                }

                for (int i = 0; i < runCount; i++)
                {
                    string repeatSuffix = i > 0 ? $" ({i + 1})" : string.Empty;

                    if (m.GetCustomAttribute(typeof(TestAttribute), false) != null)
                    {
                        hadTestAttributeTest = true;
                        CurrentTest.AddLabel($"{name}{repeatSuffix}");

                        handleTestMethod(m);
                    }

                    foreach (var tc in m.GetCustomAttributes(typeof(TestCaseAttribute), false).OfType <TestCaseAttribute>())
                    {
                        hadTestAttributeTest = true;
                        CurrentTest.AddLabel($"{name}({string.Join(", ", tc.Arguments)}){repeatSuffix}");

                        handleTestMethod(m, tc.Arguments);
                    }
                }
            }

            // even if no [Test] or [TestCase] methods were found, [SetUp] steps should be added.
            if (!hadTestAttributeTest)
            {
                addSetUpSteps();
            }

            backgroundCompiler?.SetRecompilationTarget(CurrentTest);
            runTests(onCompletion);
            updateButtons();

            void addSetUpSteps()
            {
                var setUpMethods = Reflect.GetMethodsWithAttribute(newTest.GetType(), typeof(SetUpAttribute), true)
                                   .Where(m => m.Name != nameof(TestScene.SetUpTestForNUnit));

                if (setUpMethods.Any())
                {
                    CurrentTest.AddStep(new SetUpStepButton
                    {
                        Action = () => setUpMethods.ForEach(s => s.Invoke(CurrentTest, null))
                    });
                }

                CurrentTest.RunSetUpSteps();
            }

            void handleTestMethod(MethodInfo methodInfo, object[] arguments = null)
            {
                addSetUpSteps();
                methodInfo.Invoke(CurrentTest, arguments);
                CurrentTest.RunTearDownSteps();
            }
        }
コード例 #8
0
 /// <summary>
 /// Blocks execution until a provided <see cref="TestScene"/> runs to completion.
 /// </summary>
 /// <param name="test">The <see cref="TestScene"/> to run.</param>
 public virtual void RunTestBlocking(TestScene test) => runner.RunTestBlocking(test);
コード例 #9
0
ファイル: TestBrowser.cs プロジェクト: limocute/osu-framework
        private void finishLoad(TestScene newTest, Action onCompletion)
        {
            if (CurrentTest != newTest)
            {
                // There could have been multiple loads fired after us. In such a case we want to silently remove ourselves.
                testContentContainer.Remove(newTest.Parent);
                return;
            }

            updateButtons();

            bool hadTestAttributeTest = false;

            foreach (var m in newTest.GetType().GetMethods())
            {
                var name = m.Name;

                if (name == nameof(TestScene.TestConstructor) || m.GetCustomAttribute(typeof(IgnoreAttribute), false) != null)
                {
                    continue;
                }

                if (name.StartsWith("Test", StringComparison.Ordinal))
                {
                    name = name.Substring(4);
                }

                int runCount = 1;

                if (m.GetCustomAttribute(typeof(RepeatAttribute), false) != null)
                {
                    var count = m.GetCustomAttributesData().Single(a => a.AttributeType == typeof(RepeatAttribute)).ConstructorArguments.Single().Value;
                    Debug.Assert(count != null);

                    runCount += (int)count;
                }

                for (int i = 0; i < runCount; i++)
                {
                    string repeatSuffix = i > 0 ? $" ({i + 1})" : string.Empty;

                    var methodWrapper = new MethodWrapper(m.GetType(), m);

                    if (methodWrapper.GetCustomAttributes <TestAttribute>(false).SingleOrDefault() != null)
                    {
                        var parameters = m.GetParameters();

                        if (parameters.Length > 0)
                        {
                            var valueMatrix = new List <List <object> >();

                            foreach (var p in methodWrapper.GetParameters())
                            {
                                var valueAttrib = p.GetCustomAttributes <ValuesAttribute>(false).SingleOrDefault();
                                if (valueAttrib == null)
                                {
                                    throw new ArgumentException($"Parameter is present on a {nameof(TestAttribute)} method without values specification.", p.ParameterInfo.Name);
                                }

                                List <object> choices = new List <object>();

                                foreach (var choice in valueAttrib.GetData(p))
                                {
                                    choices.Add(choice);
                                }

                                valueMatrix.Add(choices);
                            }

                            foreach (var combination in valueMatrix.CartesianProduct())
                            {
                                hadTestAttributeTest = true;
                                CurrentTest.AddLabel($"{name}({string.Join(", ", combination)}){repeatSuffix}");
                                handleTestMethod(m, combination.ToArray());
                            }
                        }
                        else
                        {
                            hadTestAttributeTest = true;
                            CurrentTest.AddLabel($"{name}{repeatSuffix}");
                            handleTestMethod(m);
                        }
                    }

                    foreach (var tc in m.GetCustomAttributes(typeof(TestCaseAttribute), false).OfType <TestCaseAttribute>())
                    {
                        hadTestAttributeTest = true;
                        CurrentTest.AddLabel($"{name}({string.Join(", ", tc.Arguments)}){repeatSuffix}");

                        handleTestMethod(m, tc.Arguments);
                    }
                }
            }

            // even if no [Test] or [TestCase] methods were found, [SetUp] steps should be added.
            if (!hadTestAttributeTest)
            {
                addSetUpSteps();
            }

            backgroundCompiler?.SetRecompilationTarget(CurrentTest);
            runTests(onCompletion);
            updateButtons();

            void addSetUpSteps()
            {
                var setUpMethods = Reflect.GetMethodsWithAttribute(newTest.GetType(), typeof(SetUpAttribute), true)
                                   .Where(m => m.Name != nameof(TestScene.SetUpTestForNUnit));

                if (setUpMethods.Any())
                {
                    CurrentTest.AddStep(new SingleStepButton(true)
                    {
                        Text        = "[SetUp]",
                        LightColour = Color4.Teal,
                        Action      = () => setUpMethods.ForEach(s => s.Invoke(CurrentTest, null))
                    });
                }

                CurrentTest.RunSetUpSteps();
            }

            void handleTestMethod(MethodInfo methodInfo, object[] arguments = null)
            {
                addSetUpSteps();
                methodInfo.Invoke(CurrentTest, arguments);
                CurrentTest.RunTearDownSteps();
            }
        }