Update Project

This commit is contained in:
2026-03-20 13:04:43 +02:00
parent 9b587e6cba
commit beae2dea89
2295 changed files with 251259 additions and 33 deletions
@@ -0,0 +1,109 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ModestTree;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zenject.Internal;
using Assert = ModestTree.Assert;
// Ignore warning about using SceneManager.UnloadScene instead of SceneManager.UnloadSceneAsync
#pragma warning disable 618
namespace Zenject
{
public abstract class SceneTestFixture
{
readonly List<DiContainer> _sceneContainers = new List<DiContainer>();
bool _hasLoadedScene;
DiContainer _sceneContainer;
protected DiContainer SceneContainer
{
get { return _sceneContainer; }
}
protected IEnumerable<DiContainer> SceneContainers
{
get { return _sceneContainers; }
}
public IEnumerator LoadScene(string sceneName)
{
return LoadScenes(sceneName);
}
public IEnumerator LoadScenes(params string[] sceneNames)
{
Assert.That(!_hasLoadedScene, "Attempted to load scene twice!");
_hasLoadedScene = true;
// Clean up any leftovers from previous test
ZenjectTestUtil.DestroyEverythingExceptTestRunner(false);
Assert.That(SceneContainers.IsEmpty());
for (int i = 0; i < sceneNames.Length; i++)
{
var sceneName = sceneNames[i];
Assert.That(Application.CanStreamedLevelBeLoaded(sceneName),
"Cannot load scene '{0}' for test '{1}'. The scenes used by SceneTestFixture derived classes must be added to the build settings for the test to work",
sceneName, GetType());
Log.Info("Loading scene '{0}' for testing", sceneName);
var loader = SceneManager.LoadSceneAsync(sceneName, i == 0 ? LoadSceneMode.Single : LoadSceneMode.Additive);
while (!loader.isDone)
{
yield return null;
}
SceneContext sceneContext = null;
if (ProjectContext.HasInstance)
// ProjectContext might be null if scene does not have a scene context
{
var scene = SceneManager.GetSceneByName(sceneName);
sceneContext = ProjectContext.Instance.Container.Resolve<SceneContextRegistry>()
.TryGetSceneContextForScene(scene);
}
_sceneContainers.Add(sceneContext == null ? null : sceneContext.Container);
}
_sceneContainer = _sceneContainers.Where(x => x != null).LastOrDefault();
if (_sceneContainer != null)
{
_sceneContainer.Inject(this);
}
}
[SetUp]
public virtual void SetUp()
{
StaticContext.Clear();
SetMemberDefaults();
}
void SetMemberDefaults()
{
_hasLoadedScene = false;
_sceneContainer = null;
_sceneContainers.Clear();
}
[TearDown]
public virtual void Teardown()
{
ZenjectTestUtil.DestroyEverythingExceptTestRunner(true);
StaticContext.Clear();
SetMemberDefaults();
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 325fb0e9bd879b440a9b5c077309c199
timeCreated: 1527233974
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEngine;
namespace Zenject
{
public class SceneTestFixtureSceneReference : ScriptableObject
{
public SceneAsset Scene;
}
}
#endif
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 5b634c456740a0e42928511e3f2ada75
timeCreated: 1527233974
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
using System;
namespace Zenject
{
[AttributeUsage(AttributeTargets.Method)]
public class ValidateOnlyAttribute : Attribute
{
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2f9f4a0ef011f8846b17c8dc23e69b11
timeCreated: 1506450521
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
{
"name": "Zenject-TestFramework",
"references": [
"Zenject"
],
"optionalUnityReferences": [
"TestAssemblies"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: a2f2239355369ba4fb6909aeaa41def5
timeCreated: 1531969421
licenseType: Free
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,155 @@
using System;
using System.Collections;
using Zenject.Internal;
using ModestTree;
using Assert = ModestTree.Assert;
using System.Linq;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using UnityEngine;
namespace Zenject
{
public abstract class ZenjectIntegrationTestFixture
{
SceneContext _sceneContext;
bool _hasEndedInstall;
bool _hasStartedInstall;
protected DiContainer Container
{
get
{
Assert.That(_hasStartedInstall,
"Must call PreInstall() before accessing ZenjectIntegrationTestFixture.Container!");
return _sceneContext.Container;
}
}
protected SceneContext SceneContext
{
get
{
Assert.That(_hasStartedInstall,
"Must call PreInstall() before accessing ZenjectIntegrationTestFixture.SceneContext!");
return _sceneContext;
}
}
[SetUp]
public void Setup()
{
Assert.That(Application.isPlaying,
"ZenjectIntegrationTestFixture is meant to be used for play mode tests only. Please ensure your test file '{0}' is outside of the editor folder and try again.", GetType());
ZenjectTestUtil.DestroyEverythingExceptTestRunner(true);
StaticContext.Clear();
}
protected void SkipInstall()
{
PreInstall();
PostInstall();
}
protected void PreInstall()
{
Assert.That(!_hasStartedInstall, "Called PreInstall twice in test '{0}'!", TestContext.CurrentContext.Test.Name);
_hasStartedInstall = true;
Assert.That(!ProjectContext.HasInstance);
var shouldValidate = CurrentTestHasAttribute<ValidateOnlyAttribute>();
ProjectContext.ValidateOnNextRun = shouldValidate;
Assert.That(_sceneContext == null);
_sceneContext = SceneContext.Create();
_sceneContext.Install();
Assert.That(ProjectContext.HasInstance);
Assert.IsEqual(shouldValidate, ProjectContext.Instance.Container.IsValidating);
Assert.IsEqual(shouldValidate, _sceneContext.Container.IsValidating);
}
bool CurrentTestHasAttribute<T>()
where T : Attribute
{
return GetType().GetMethod(TestContext.CurrentContext.Test.MethodName)
.GetCustomAttributes(true)
.Cast<Attribute>().OfType<T>().Any();
}
protected void PostInstall()
{
Assert.That(_hasStartedInstall,
"Called PostInstall but did not call PreInstall in test '{0}'!", TestContext.CurrentContext.Test.Name);
Assert.That(!_hasEndedInstall, "Called PostInstall twice in test '{0}'!", TestContext.CurrentContext.Test.Name);
_hasEndedInstall = true;
_sceneContext.Resolve();
Container.Inject(this);
if (!Container.IsValidating)
{
// We don't have to do this here but it's kind of convenient
// We could also remove it and just require that users add a yield after calling
// and it would have the same effect
Container.Resolve<MonoKernel>().Initialize();
}
}
protected IEnumerator DestroyEverything()
{
Assert.That(_hasStartedInstall,
"Called DestroyAll but did not call PreInstall (or SkipInstall) in test '{0}'!", TestContext.CurrentContext.Test.Name);
DestroyEverythingInternal(false);
// Wait one frame for GC to really destroy everything
yield return null;
}
void DestroyEverythingInternal(bool immediate)
{
if (_sceneContext != null)
{
// We need to use DestroyImmediate so that all the IDisposable's etc get processed immediately before
// next test runs
if (immediate)
{
GameObject.DestroyImmediate(_sceneContext.gameObject);
}
else
{
GameObject.Destroy(_sceneContext.gameObject);
}
_sceneContext = null;
}
ZenjectTestUtil.DestroyEverythingExceptTestRunner(immediate);
StaticContext.Clear();
}
[TearDown]
public void TearDown()
{
if (TestContext.CurrentContext.Result.Outcome == ResultState.Success)
{
Assert.That(_hasStartedInstall,
"PreInstall (or SkipInstall) was not called in test '{0}'!", TestContext.CurrentContext.Test.Name);
Assert.That(_hasEndedInstall,
"PostInstall was not called in test '{0}'!", TestContext.CurrentContext.Test.Name);
}
DestroyEverythingInternal(true);
_hasStartedInstall = false;
_hasEndedInstall = false;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e0464fe2b382d1d4babf13bf0c3fa044
timeCreated: 1506429461
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,49 @@
using ModestTree;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Zenject.Internal
{
public static class ZenjectTestUtil
{
public const string UnitTestRunnerGameObjectName = "Code-based tests runner";
public static void DestroyEverythingExceptTestRunner(bool immediate)
{
var testRunner = GameObject.Find(UnitTestRunnerGameObjectName);
Assert.IsNotNull(testRunner);
GameObject.DontDestroyOnLoad(testRunner);
// We want to clear all objects across all scenes to ensure the next test is not affected
// at all by previous tests
for (int i = 0; i < SceneManager.sceneCount; i++)
{
foreach (var obj in SceneManager.GetSceneAt(i).GetRootGameObjects())
{
GameObject.DestroyImmediate(obj);
}
}
if (ProjectContext.HasInstance)
{
var dontDestroyOnLoadRoots = ProjectContext.Instance.gameObject.scene
.GetRootGameObjects();
foreach (var rootObj in dontDestroyOnLoadRoots)
{
if (rootObj.name != UnitTestRunnerGameObjectName)
{
if (immediate)
{
GameObject.DestroyImmediate(rootObj);
}
else
{
GameObject.Destroy(rootObj);
}
}
}
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 4101e443fc2ede94c99d4d759087cc44
timeCreated: 1527644566
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,31 @@
using NUnit.Framework;
namespace Zenject
{
// Inherit from this and mark you class with [TestFixture] attribute to do some unit tests
// For anything more complicated than this, such as tests involving interaction between
// several classes, or if you want to use interfaces such as IInitializable or IDisposable,
// then I recommend using ZenjectIntegrationTestFixture instead
// See documentation for details
public abstract class ZenjectUnitTestFixture
{
DiContainer _container;
protected DiContainer Container
{
get { return _container; }
}
[SetUp]
public virtual void Setup()
{
_container = new DiContainer(StaticContext.Container);
}
[TearDown]
public virtual void Teardown()
{
StaticContext.Clear();
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 51305c7ccfc8a9f4390aeefc54674cde
timeCreated: 1536808207
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: