// Copyright (c) Craftwork Games. All rights reserved. // Licensed under the MIT license. // See LICENSE file in the project root for full license information. using System; using System.IO; using System.Xml; using Microsoft.Xna.Framework; using MonoGame.Extended.Particles; using MonoGame.Extended.Particles.Modifiers; using MonoGame.Extended.Particles.Modifiers.Containers; using MonoGame.Extended.Particles.Modifiers.Interpolators; using MonoGame.Extended.Particles.Profiles; namespace MonoGame.Extended.Tests.Particles; public class ParticleEffectReaderTests { private readonly MockContentManager _mockContentManager; public ParticleEffectReaderTests() { _mockContentManager = new MockContentManager(); } private ParticleEffect ReadParticleEffectFromXml(string xml) { using MemoryStream stream = new MemoryStream(); using StreamWriter writer = new StreamWriter(stream); writer.Write(xml); writer.Flush(); stream.Position = 0; using ParticleEffectReader reader = new ParticleEffectReader(stream, _mockContentManager); return reader.ReadParticleEffect(); } [Fact] public void ReadParticleEffect_NulLStream_ThrowsArgumentNullException() { Assert.Throws(() => new ParticleEffectReader((Stream)null, _mockContentManager)); } [Fact] public void ReadParticleEffect_NullContentManager_ThrowsArgumentNullException() { using MemoryStream stream = new MemoryStream(); Assert.Throws(() => new ParticleEffectReader(stream, null)); } [Fact] public void ReadParticleEffect_InvalidXmlRoot_ThrowsXmlException() { string xml = ""; Assert.Throws(() => ReadParticleEffectFromXml(xml)); } [Fact] public void ReadParticleEffect_EmptyEffect_ReturnsExpected() { string xml = """ """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Equal("EmptyEffect", effect.Name); Assert.Equal(Vector2.Zero, effect.Position); Assert.Equal(0.0f, effect.Rotation); Assert.Equal(Vector2.One, effect.Scale); Assert.Empty(effect.Emitters); Assert.True(effect.AutoTrigger); Assert.Equal(effect.AutoTriggerFrequency, 1.0f); } [Fact] public void ReadParticleEffect_EmptyModifiers_ReturnsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Empty(emitter.Modifiers); } [Fact] public void ReadParticleEffect_EmptyInterpolators_ReturnsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; AgeModifier modifier = Assert.IsType(emitter.Modifiers[0]); Assert.Empty(modifier.Interpolators); } [Fact] public void ReadParticleEffect_BoxFillProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; BoxFillProfile profile = Assert.IsType(emitter.Profile); Assert.Equal(1.0f, profile.Height); Assert.Equal(1.0f, profile.Height); } [Fact] public void ReadParticleEffect_BoxProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; BoxProfile profile = Assert.IsType(emitter.Profile); Assert.Equal(1.0f, profile.Height); Assert.Equal(1.0f, profile.Height); } [Fact] public void ReadParticleEffect_BoxUniformProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; BoxUniformProfile profile = Assert.IsType(emitter.Profile); Assert.Equal(1.0f, profile.Height); Assert.Equal(1.0f, profile.Height); } [Fact] public void ReadParticleEffect_CircleProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; CircleProfile profile = Assert.IsType(emitter.Profile); Assert.Equal(1.0f, profile.Radius); Assert.Equal(CircleRadiation.Out, profile.Radiate); } [Fact] public void ReadParticleEffect_LineProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; LineProfile profile = Assert.IsType(emitter.Profile); Assert.Equal(Vector2.One, profile.Axis); Assert.Equal(1.0f, profile.Length); } [Fact] public void ReadParticleEffect_PointProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; PointProfile profile = Assert.IsType(emitter.Profile); } [Fact] public void ReadParticleEffect_RingProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; RingProfile profile = Assert.IsType(emitter.Profile); Assert.Equal(1.0f, profile.Radius); Assert.Equal(CircleRadiation.In, profile.Radiate); } [Fact] public void ReadParticleEffect_SprayProfile_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; SprayProfile profile = Assert.IsType(emitter.Profile); Assert.Equal(Vector2.One, profile.Direction); Assert.Equal(1.0f, profile.Spread); } [Fact] public void ReadParticleEffect_AgeModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); AgeModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("AgeModifier", modifier.Name); } [Fact] public void ReadParticleEffect_CircleContainerModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); CircleContainerModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("CircleContainerModifier", modifier.Name); Assert.Equal(0.0f, modifier.Radius); Assert.True(modifier.Inside); Assert.Equal(1.0f, modifier.RestitutionCoefficient); } [Fact] public void ReadParticleEffect_DragModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); DragModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("DragModifier", modifier.Name); Assert.Equal(0.47f, modifier.DragCoefficient); Assert.Equal(0.5f, modifier.Density); } [Fact] public void ReadParticleEffect_LinearGravityModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); LinearGravityModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("LinearGravityModifier", modifier.Name); Assert.Equal(Vector2.Zero, modifier.Direction); Assert.Equal(0.0f, modifier.Strength); } [Fact] public void ReadParticleEffect_OpacityFastFadeModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); OpacityFastFadeModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("OpacityFastFadeModifier", modifier.Name); } [Fact] public void ReadParticleEffect_RectangleContainerModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); RectangleContainerModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("RectangleContainerModifier", modifier.Name); Assert.Equal(0.0f, modifier.Width); Assert.Equal(0.0f, modifier.Height); Assert.Equal(1.0f, modifier.RestitutionCoefficient); } [Fact] public void ReadParticleEffect_RectangleLoopContainerModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); RectangleLoopContainerModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("RectangleLoopContainerModifier", modifier.Name); Assert.Equal(0.0f, modifier.Width); Assert.Equal(0.0f, modifier.Height); } [Fact] public void ReadParticleEffect_RotationModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); RotationModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("RotationModifier", modifier.Name); Assert.Equal(0.0f, modifier.RotationRate); } [Fact] public void ReadParticleEffect_VelocityColorModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); VelocityColorModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("VelocityColorModifier", modifier.Name); Assert.Equal(new HslColor(0, 0, 0), modifier.StationaryColor); Assert.Equal(new HslColor(0, 0, 0), modifier.VelocityColor); Assert.Equal(0.0f, modifier.VelocityThreshold); } [Fact] public void ReadParticleEffect_VelocityModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); VelocityModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("VelocityModifier", modifier.Name); Assert.Equal(0.0f, modifier.VelocityThreshold); } [Fact] public void ReadParticleEffect_VortexModifier_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); VortexModifier modifier = Assert.IsType(effect.Emitters[0].Modifiers[0]); Assert.Equal(60.0f, modifier.Frequency); Assert.Equal("VortexModifier", modifier.Name); Assert.Equal(Vector2.Zero, modifier.Position); Assert.Equal(1.0f, modifier.Strength); Assert.Equal(2.0f, modifier.OuterRadius); Assert.Equal(3.0f, modifier.InnerRadius); Assert.Equal(4.0f, modifier.MaxVelocity); Assert.Equal(5.0f, modifier.RotationAngle); } [Fact] public void ReadParticleEffect_ColorInterpolator_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); AgeModifier modifier = Assert.IsType(emitter.Modifiers[0]); Assert.Single(modifier.Interpolators); ColorInterpolator interpolator = Assert.IsType(modifier.Interpolators[0]); Assert.Equal(new HslColor(0, 0, 0), interpolator.StartValue); Assert.Equal(new HslColor(0, 0, 0), interpolator.EndValue); } [Fact] public void ReadParticleEffect_HueInterpolator_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); AgeModifier modifier = Assert.IsType(emitter.Modifiers[0]); Assert.Single(modifier.Interpolators); HueInterpolator interpolator = Assert.IsType(modifier.Interpolators[0]); Assert.Equal(0.0f, interpolator.StartValue); Assert.Equal(0.0f, interpolator.EndValue); } [Fact] public void ReadParticleEffect_OpacityInterpolator_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); AgeModifier modifier = Assert.IsType(emitter.Modifiers[0]); Assert.Single(modifier.Interpolators); OpacityInterpolator interpolator = Assert.IsType(modifier.Interpolators[0]); Assert.Equal(0.0f, interpolator.StartValue); Assert.Equal(0.0f, interpolator.EndValue); } [Fact] public void ReadParticleEffect_RotationInterpolator_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); AgeModifier modifier = Assert.IsType(emitter.Modifiers[0]); Assert.Single(modifier.Interpolators); RotationInterpolator interpolator = Assert.IsType(modifier.Interpolators[0]); Assert.Equal(0.0f, interpolator.StartValue); Assert.Equal(0.0f, interpolator.EndValue); } [Fact] public void ReadParticleEffect_ScaleInterpolator_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); AgeModifier modifier = Assert.IsType(emitter.Modifiers[0]); Assert.Single(modifier.Interpolators); ScaleInterpolator interpolator = Assert.IsType(modifier.Interpolators[0]); Assert.Equal(Vector2.Zero, interpolator.StartValue); Assert.Equal(Vector2.One, interpolator.EndValue); } [Fact] public void ReadParticleEffect_VelocityInterpolator_ReadsExpected() { string xml = $""" """; ParticleEffect effect = ReadParticleEffectFromXml(xml); Assert.Single(effect.Emitters); ParticleEmitter emitter = effect.Emitters[0]; Assert.Single(emitter.Modifiers); AgeModifier modifier = Assert.IsType(emitter.Modifiers[0]); Assert.Single(modifier.Interpolators); VelocityInterpolator interpolator = Assert.IsType(modifier.Interpolators[0]); Assert.Equal(Vector2.Zero, interpolator.StartValue); Assert.Equal(Vector2.Zero, interpolator.EndValue); } }