From dfd28160a0af6c6a83fe2fa14e557601d6434568 Mon Sep 17 00:00:00 2001 From: Gawaboumga Date: Wed, 31 Jan 2018 15:27:23 +0100 Subject: [PATCH 1/2] Lua tests (#158) * Fix float comparison in tests * Lua tests --- tests/Engine/Lua/LuaClass.cpp | 249 ++++++++++++++++++++ tests/Engine/Lua/LuaCoroutine.cpp | 31 +++ tests/Engine/Lua/LuaInstance.cpp | 84 +++++++ tests/Engine/Lua/LuaState.cpp | 187 +++++++++++++++ tests/Engine/Physics2D/Collider2D.cpp | 2 +- tests/Engine/Physics2D/RigidBody2D.cpp | 6 +- tests/SDK/NDK/Systems/PhysicsSystem2D.cpp | 2 +- tests/resources/Engine/Lua/LuaClass.lua | 24 ++ tests/resources/Engine/Lua/LuaCoroutine.lua | 15 ++ 9 files changed, 595 insertions(+), 5 deletions(-) create mode 100644 tests/Engine/Lua/LuaClass.cpp create mode 100644 tests/Engine/Lua/LuaCoroutine.cpp create mode 100644 tests/Engine/Lua/LuaInstance.cpp create mode 100644 tests/Engine/Lua/LuaState.cpp create mode 100644 tests/resources/Engine/Lua/LuaClass.lua create mode 100644 tests/resources/Engine/Lua/LuaCoroutine.lua diff --git a/tests/Engine/Lua/LuaClass.cpp b/tests/Engine/Lua/LuaClass.cpp new file mode 100644 index 000000000..b6963a3bd --- /dev/null +++ b/tests/Engine/Lua/LuaClass.cpp @@ -0,0 +1,249 @@ +#include +#include +#include +#include + +class Test +{ + public: + Test() = default; + Test(const Test& other) = default; + Test& operator=(const Test& other) = default; + virtual ~Test() = default; + + Test(int i, bool j = false) : + m_i(i), + m_j(j) + { + } + + virtual int GetI() const + { + return m_i; + } + + bool GetJ() const + { + return m_j; + } + + int GetDefault(int defaultValue = 0) + { + return defaultValue; + } + + static int StaticMethodWithArguments(int a, int b) + { + return a + b; + } + + private: + int m_i; + bool m_j; +}; + +class InheritTest : public Test +{ + public: + InheritTest() : + Test(5, true) + { + } + + int GetI() const override + { + return Test::GetI() + 3; + } +}; + +class TestWithHandle : public Nz::HandledObject +{ + public: + int GetI() const + { + return m_i; + } + + int GetDefault(int defaultValue = 0) + { + return defaultValue; + } + + private: + int m_i = 8; +}; + +inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, Test* arg, Nz::TypeTag) +{ + REQUIRE(instance.IsOfType(index, "Test")); + *arg = *static_cast(instance.ToUserdata(index)); + return 1; +} + +inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, Nz::ObjectHandle* arg, Nz::TypeTag>) +{ + REQUIRE(instance.IsOfType(index, "TestWithHandle")); + *arg = *static_cast*>(instance.ToUserdata(index)); + return 1; +} + +inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, InheritTest* arg, Nz::TypeTag) +{ + REQUIRE(instance.IsOfType(index, "InheritTest")); + *arg = *static_cast(instance.ToUserdata(index)); + return 1; +} + +SCENARIO("LuaClass", "[LUA][LUACLASS]") +{ + GIVEN("One lua class for our Test class") + { + Nz::LuaInstance luaInstance; + Nz::LuaClass test; + Nz::LuaClass inheritTest; + using TestHandle = Nz::ObjectHandle; + Nz::LuaClass testHandle; + + WHEN("We bind the methods") + { + test.Reset("Test"); + + test.BindDefaultConstructor(); + + test.SetConstructor([] (Nz::LuaState& lua, Test* instance, std::size_t argumentCount) + { + std::size_t argCount = std::min(argumentCount, 2U); + + int argIndex = 1; + switch (argCount) + { + case 1: + { + int iValue = lua.Check(&argIndex, 0); + + Nz::PlacementNew(instance, iValue); + return true; + } + + case 2: + { + int iValue = lua.Check(&argIndex, 0); + bool j = lua.Check(&argIndex, false); + + Nz::PlacementNew(instance, iValue, j); + return true; + } + } + + lua.Error("No matching overload for Test constructor"); + return false; + }); + + test.BindMethod("GetI", &Test::GetI); + test.BindMethod("GetJ", &Test::GetJ); + test.BindMethod("GetDefault", &Test::GetDefault, 0); + + test.BindStaticMethod("StaticMethodWithArguments", [] (Nz::LuaState& state) -> int + { + int argIndex = 1; + int result = Test::StaticMethodWithArguments(state.Check(&argIndex), state.Check(&argIndex)); + + state.Push(result); + return 1; + }); + + test.Register(luaInstance); + + THEN("We should be able to call them") + { + int value = 1; + int staticResult = value + value; + + luaInstance.PushFunction([=](Nz::LuaState& state) -> int + { + int argIndex = 1; + Test result = state.Check(&argIndex); + CHECK(result.GetI() == value); + CHECK_FALSE(result.GetJ()); + return 1; + }); + luaInstance.SetGlobal("CheckTest"); + + luaInstance.PushFunction([=](Nz::LuaState& state) -> int + { + int argIndex = 1; + int result = state.Check(&argIndex); + CHECK(result == staticResult); + return 1; + }); + luaInstance.SetGlobal("CheckStatic"); + + luaInstance.PushFunction([=](Nz::LuaState& state) -> int + { + int argIndex = 1; + Test result = state.Check(&argIndex); + CHECK(result.GetI() == staticResult); + CHECK(result.GetJ()); + return 1; + }); + luaInstance.SetGlobal("CheckFinalTest"); + + REQUIRE(luaInstance.ExecuteFromFile("resources/Engine/Lua/LuaClass.lua")); + REQUIRE(luaInstance.GetGlobal("test_Test") == Nz::LuaType_Function); + luaInstance.Call(0); + } + + AND_THEN("With a subclass") + { + inheritTest.Reset("InheritTest"); + + inheritTest.Inherit(test); + inheritTest.BindDefaultConstructor(); + + inheritTest.Register(luaInstance); + + luaInstance.PushFunction([=](Nz::LuaState& state) -> int + { + int argIndex = 1; + InheritTest result = state.Check(&argIndex); + CHECK(result.GetI() == 8); + CHECK(result.GetJ()); + return 1; + }); + luaInstance.SetGlobal("CheckInheritTest"); + + REQUIRE(luaInstance.ExecuteFromFile("resources/Engine/Lua/LuaClass.lua")); + REQUIRE(luaInstance.GetGlobal("test_InheritTest") == Nz::LuaType_Function); + luaInstance.Call(0); + } + } + + WHEN("We bind the object with Handle") + { + int defaultValue = 5; + + testHandle.Reset("TestHandle"); + testHandle.BindMethod("IsValid", &TestHandle::IsValid); + testHandle.BindMethod("GetI", &TestWithHandle::GetI); + testHandle.BindMethod("GetDefault", &TestWithHandle::GetDefault, defaultValue); + testHandle.Register(luaInstance); + + THEN("We can ensure the following properties") + { + luaInstance.PushFunction([=](Nz::LuaState& state) -> int + { + int argIndex = 1; + TestHandle result = state.Check(&argIndex); + CHECK(result->GetI() == 8); + CHECK(result->GetDefault() == defaultValue); + return 1; + }); + luaInstance.SetGlobal("CheckTestHandle"); + + REQUIRE(luaInstance.ExecuteFromFile("resources/Engine/Lua/LuaClass.lua")); + REQUIRE(luaInstance.GetGlobal("test_TestHandle") == Nz::LuaType_Function); + luaInstance.Call(0); + } + } + } +} diff --git a/tests/Engine/Lua/LuaCoroutine.cpp b/tests/Engine/Lua/LuaCoroutine.cpp new file mode 100644 index 000000000..3ab42d6b9 --- /dev/null +++ b/tests/Engine/Lua/LuaCoroutine.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +SCENARIO("LuaCoroutine", "[LUA][LUACOROUTINE]") +{ + GIVEN("One lua with coroutine") + { + Nz::LuaInstance luaInstance; + luaInstance.LoadLibraries(Nz::LuaLib_Coroutine); + + REQUIRE(luaInstance.ExecuteFromFile("resources/Engine/Lua/LuaCoroutine.lua")); + + Nz::LuaCoroutine coroutine = luaInstance.NewCoroutine(); + REQUIRE(coroutine.GetGlobal("infinite") == Nz::LuaType_Function); + coroutine.PushInteger(4); + CHECK(coroutine.Call(1)); + + coroutine.Resume(); + CHECK(coroutine.CheckInteger(1) == 1); + coroutine.Resume(); + CHECK(coroutine.CheckInteger(1) == -1); + coroutine.Resume(); + CHECK(coroutine.CheckInteger(1) == 0); + coroutine.Resume(); + CHECK(coroutine.CheckInteger(1) == 1); + + coroutine.Resume(); + CHECK_FALSE(coroutine.CanResume()); + } +} diff --git a/tests/Engine/Lua/LuaInstance.cpp b/tests/Engine/Lua/LuaInstance.cpp new file mode 100644 index 000000000..6042704bf --- /dev/null +++ b/tests/Engine/Lua/LuaInstance.cpp @@ -0,0 +1,84 @@ +#include +#include +#include + +SCENARIO("LuaInstance", "[LUA][LUAINSTANCE]") +{ + GIVEN("One lua instance") + { + Nz::LuaInstance luaInstance; + + WHEN("We set memory constraint") + { + luaInstance.SetMemoryLimit(1'000); + + THEN("If we excess memory, it should crash") + { + REQUIRE_THROWS_WITH(luaInstance.Execute(R"( + global t = {} + for 1,10000000 do + t[i] = i + end + )"), Catch::Matchers::Contains("memory")); + } + } + + WHEN("We set time constraint") + { + luaInstance.SetTimeLimit(10); + + THEN("If we excess time, it should produce an error") + { + CHECK(!luaInstance.Execute(R"( + function ack(M,N) + if M == 0 then return N + 1 end + if N == 0 then return ack(M-1,1) end + return ack(M-1,ack(M, N-1)) + end + ack(100, 100) + )")); + + REQUIRE_THAT(luaInstance.GetLastError().ToStdString(), Catch::Matchers::Contains("time")); + } + } + } + + GIVEN("Two instances") + { + Nz::LuaInstance luaInstance; + + int memoryLimit = 10'000; + int timeLimit = 1'000; + luaInstance.SetMemoryLimit(memoryLimit); + luaInstance.SetTimeLimit(timeLimit); + + int value = 5; + luaInstance.PushInteger(value); + + WHEN("We use move constructor") + { + Nz::LuaInstance movedInstance(std::move(luaInstance)); + + THEN("We should be able to retrieve the value") + { + CHECK(movedInstance.CheckInteger(1) == value); + CHECK(movedInstance.GetMemoryLimit() == memoryLimit); + CHECK(movedInstance.GetTimeLimit() == timeLimit); + } + } + + WHEN("We use move assignment") + { + Nz::LuaInstance movedInstance; + movedInstance.PushInteger(value + 1); + movedInstance = std::move(luaInstance); + + THEN("We should be able to retrieve the value") + { + CHECK(movedInstance.CheckInteger(1) == value); + CHECK(movedInstance.GetMemoryLimit() == memoryLimit); + CHECK(movedInstance.GetTimeLimit() == timeLimit); + } + } + } +} diff --git a/tests/Engine/Lua/LuaState.cpp b/tests/Engine/Lua/LuaState.cpp new file mode 100644 index 000000000..ef2965517 --- /dev/null +++ b/tests/Engine/Lua/LuaState.cpp @@ -0,0 +1,187 @@ +#include +#include + +static int counter(lua_State* L) +{ + Nz::LuaInstance& luaInstance = Nz::LuaInstance::GetInstance(L); + double val = luaInstance.ToNumber(luaInstance.GetIndexOfUpValue(1)); + luaInstance.PushNumber(++val); + luaInstance.PushValue(-1); + luaInstance.Replace(luaInstance.GetIndexOfUpValue(1)); + return 1; +} + +struct TestLuaState +{ + int a = 3; + float b = 5.f; +}; + +struct TestMetaTable +{ + float x = 1.f; + float y = 2.f; +}; + +inline int LuaImplReplyVal(const Nz::LuaState& state, TestLuaState&& val, Nz::TypeTag) +{ + state.PushTable(); + state.PushField("a", val.a); + state.PushField("b", val.b); + + return 1; +} + +inline unsigned int LuaImplQueryArg(const Nz::LuaState& state, int index, TestLuaState* arg, Nz::TypeTag) +{ + state.CheckType(index, Nz::LuaType_Table); + + arg->a = state.CheckField("a", index); + arg->b = state.CheckField("b", index); + + return 1; +} + +SCENARIO("LuaState", "[LUA][LUASTATE]") +{ + GIVEN("One lua instance") + { + Nz::LuaInstance luaInstance; + luaInstance.LoadLibraries(Nz::LuaLib_Math); + + WHEN("We push different primitive types") + { + bool booleanValue = true; + long long integerValue = 5LL; + double doubleValue = -55.0; + const char* stringValue = "test"; + Nz::String nazaraValue = "Nazara"; + luaInstance.PushBoolean(booleanValue); + luaInstance.PushInteger(integerValue); + luaInstance.PushNil(); + luaInstance.PushNumber(doubleValue); + luaInstance.PushString(stringValue); + luaInstance.PushString(nazaraValue); + + THEN("We should be able to retrieve them") + { + CHECK(luaInstance.CheckBoolean(1) == booleanValue); + CHECK(luaInstance.CheckInteger(2) == integerValue); + bool succeeded = false; + CHECK(luaInstance.ToInteger(2, &succeeded) == integerValue); + CHECK(succeeded); + CHECK(luaInstance.ToPointer(3) == nullptr); + CHECK(luaInstance.CheckNumber(4) == Approx(doubleValue)); + succeeded = false; + CHECK(luaInstance.ToNumber(4, &succeeded) == Approx(doubleValue)); + CHECK(succeeded); + CHECK(luaInstance.CheckString(5) == std::string(stringValue)); + CHECK(luaInstance.CheckString(6) == nazaraValue); + std::size_t length = 0; + CHECK(luaInstance.ToString(6, &length) == nazaraValue); + CHECK(length == nazaraValue.GetSize()); + } + } + + WHEN("We use basic operations") + { + luaInstance.PushInteger(1); + luaInstance.PushInteger(2); + + THEN("We should behave normally") + { + CHECK(luaInstance.Compare(1, 2, Nz::LuaComparison_Less)); + luaInstance.Compute(Nz::LuaOperation_Substraction); + CHECK(luaInstance.ToInteger(1) == -1); + } + } + + WHEN("We manipulate the stack") + { + Nz::String stringValue = "hello"; + luaInstance.PushBoolean(true); + luaInstance.PushNumber(10.0); + luaInstance.PushNil(); + luaInstance.PushString(stringValue); + /* true 10.0 nil hello */ + + THEN("These effects are expected") + { + luaInstance.PushValue(-4); + /* true 10.0 nil hello true */ + CHECK(luaInstance.CheckBoolean(5)); + + luaInstance.Replace(3); + /* true 10.0 true hello */ + CHECK(luaInstance.CheckBoolean(3)); + + luaInstance.Remove(-2); + /* true 10.0 hello */ + CHECK(luaInstance.CheckString(3) == stringValue); + + luaInstance.Pop(2); + /* true */ + CHECK_FALSE(luaInstance.IsValid(2)); + } + } + + WHEN("We try the CFunction") + { + double counterValue = 55.0; + luaInstance.PushFunction([=](Nz::LuaState& s) -> int { + s.PushNumber(counterValue); + s.PushCFunction(&counter, 1); + return 1; + }); + + THEN("We can call them") + { + luaInstance.Call(0); // We call our counter creator + luaInstance.Call(0); // We call our counter, which increments the value + CHECK(luaInstance.ToNumber(0) == Approx(counterValue + 1.0)); + } + } + + WHEN("We push our user type locally") + { + luaInstance.Push(TestLuaState()); + + THEN("We can retrieve it") + { + int index = 1; + TestLuaState popped = luaInstance.Check(&index); + CHECK(popped.a == 3); + CHECK(popped.b == Approx(5.0)); + } + } + + WHEN("We push our user type globally") + { + luaInstance.PushGlobal("TestLuaState", TestLuaState()); + + THEN("We can retrieve it") + { + TestLuaState popped = luaInstance.CheckGlobal("TestLuaState"); + CHECK(popped.a == 3); + CHECK(popped.b == Approx(5.0)); + } + } + + WHEN("We define a lua function") + { + luaInstance.Execute(R"( + function f (x, y) + return (x^2 * math.sin(y))/(1 - x) + end + )"); + + THEN("We can call it from the code") + { + REQUIRE(luaInstance.GetGlobal("f") == Nz::LuaType_Function); + luaInstance.Push(3.0, 2.0); + luaInstance.Call(2, 1); + CHECK(luaInstance.ToNumber(1) == Approx(-4.09).margin(0.1)); + } + } + } +} diff --git a/tests/Engine/Physics2D/Collider2D.cpp b/tests/Engine/Physics2D/Collider2D.cpp index dee2b85c8..811b75ded 100644 --- a/tests/Engine/Physics2D/Collider2D.cpp +++ b/tests/Engine/Physics2D/Collider2D.cpp @@ -98,7 +98,7 @@ SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") THEN("We expect those to be true") { CHECK(segment.GetFirstPoint() == firstPoint); - CHECK(segment.GetLength() == firstPoint.Distance(secondPoint)); + CHECK(segment.GetLength() == Approx(firstPoint.Distance(secondPoint))); CHECK(segment.GetSecondPoint() == secondPoint); CHECK(segment.GetType() == Nz::ColliderType2D_Segment); } diff --git a/tests/Engine/Physics2D/RigidBody2D.cpp b/tests/Engine/Physics2D/RigidBody2D.cpp index b5d0a1ec2..d524c07fd 100644 --- a/tests/Engine/Physics2D/RigidBody2D.cpp +++ b/tests/Engine/Physics2D/RigidBody2D.cpp @@ -306,13 +306,13 @@ Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world) void EQUALITY(const Nz::RigidBody2D& left, const Nz::RigidBody2D& right) { CHECK(left.GetAABB() == right.GetAABB()); - CHECK(left.GetAngularVelocity() == right.GetAngularVelocity()); + CHECK(left.GetAngularVelocity() == Approx(right.GetAngularVelocity())); CHECK(left.GetCenterOfGravity() == right.GetCenterOfGravity()); CHECK(left.GetGeom() == right.GetGeom()); CHECK(left.GetHandle() != right.GetHandle()); - CHECK(left.GetMass() == right.GetMass()); + CHECK(left.GetMass() == Approx(right.GetMass())); CHECK(left.GetPosition() == right.GetPosition()); - CHECK(left.GetRotation() == right.GetRotation()); + CHECK(left.GetRotation() == Approx(right.GetRotation())); CHECK(left.GetUserdata() == right.GetUserdata()); CHECK(left.GetVelocity() == right.GetVelocity()); } diff --git a/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp index 9173ab167..6de7b2172 100644 --- a/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp +++ b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp @@ -89,7 +89,7 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") THEN("It should have been rotated") { - CHECK(physicsComponent2D.GetAngularVelocity() == angularSpeed); + CHECK(physicsComponent2D.GetAngularVelocity() == Approx(angularSpeed)); CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(-2.f, 0.f, 2.f, 1.f)); CHECK(physicsComponent2D.GetRotation() == Approx(Nz::FromDegrees(90.f))); CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Approx(Nz::FromDegrees(90.f))); diff --git a/tests/resources/Engine/Lua/LuaClass.lua b/tests/resources/Engine/Lua/LuaClass.lua new file mode 100644 index 000000000..3434a7d94 --- /dev/null +++ b/tests/resources/Engine/Lua/LuaClass.lua @@ -0,0 +1,24 @@ + +function test_Test() + local test = Test(1) + + local i = test:GetI() + local result = Test.StaticMethodWithArguments(i, i) + local finalTest = Test(result + test:GetDefault(), true) + + CheckTest(test) + CheckStatic(result) + CheckFinalTest(finalTest) +end + +function test_InheritTest() + local test = InheritTest() + + CheckInheritTest(test) +end + +function test_TestHandle() + local test = TestHandle() + + CheckTestHandle() +end diff --git a/tests/resources/Engine/Lua/LuaCoroutine.lua b/tests/resources/Engine/Lua/LuaCoroutine.lua new file mode 100644 index 000000000..4a235cbe5 --- /dev/null +++ b/tests/resources/Engine/Lua/LuaCoroutine.lua @@ -0,0 +1,15 @@ + +function even (x) + coroutine.yield(1) +end + +function odd (x) + coroutine.yield(0) +end + +function infinite (x) + for i=1,x do + if i==3 then coroutine.yield(-1) end + if i % 2 == 0 then even(i) else odd(i) end + end +end From 1b7f1227a39d18825e6657895b75fef59214375a Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 4 Feb 2018 13:48:04 +0100 Subject: [PATCH 2/2] Update readme --- readme.md | 9 +++++---- readme_fr.md | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/readme.md b/readme.md index 2c470a751..9622f6327 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,7 @@ You can use it in any kind of commercial/non-commercial applications without any ## Authors Jérôme "Lynix" Leclercq - main developper () -Rémi "overdrivr" Bèges - developper & helper - Noise Module - () +Full Cycle Games - sponsor and contributor since January 2017. ## Install @@ -45,7 +45,8 @@ You can find tutorials on installation, compilation and use on the [official wik ## Thanks to: -- **RafBill** and **Raakz:** Finding bugs and/or testing -- **Fissal "DrFisher" Hannoun**: Helping a lot in architecture design -- **Alexandre "Danman" Janniaux**: Helping making the POSIX implementation +- **RafBill** and **Raakz:** Finding bugs and/or testing. +- **Fissal "DrFisher" Hannoun**: Helping a lot in architecture design. +- **Alexandre "Danman" Janniaux**: Helping making the POSIX implementation. - **Youri "Gawaboumga" Hubaut**: Improving the whole project by making the documentation, improving the code, and more. +- **Rémi "overdrivr" Bèges**: Made the Noise module. diff --git a/readme_fr.md b/readme_fr.md index 639ef666c..bc36005b2 100644 --- a/readme_fr.md +++ b/readme_fr.md @@ -15,7 +15,7 @@ Vous pouvez également l'utiliser pour toute application commerciale sans aucune ## Auteurs Jérôme "Lynix" Leclercq - développeur principal () -Rémi "overdrivr" Bèges - développeur & aide - module Noise - () +Full Cycle Games - sponsor et contributeur depuis Janvier 2017. ## Installation @@ -45,7 +45,8 @@ Vous pouvez lire des tutoriaux sur l'installation, la compilation et l'utilisati ### Remerciements: -- **RafBill** et **Raakz:** Recherche de bugs et/ou tests -- **Fissal "DrFisher" Hannoun**: Aide et conseils lors de la conception de l'architecture du moteur -- **Alexandre "Danman" Janniaux**: Aide sur l'implémentation POSIX +- **RafBill** et **Raakz:** Recherche de bugs et/ou tests. +- **Fissal "DrFisher" Hannoun**: Aide et conseils lors de la conception de l'architecture du moteur. +- **Alexandre "Danman" Janniaux**: Aide sur l'implémentation POSIX. - **Youri "Gawaboumga" Hubaut**: Amélioration du moteur tant au niveau du code que de sa documentation et du projet en général. +- **Rémi "overdrivr" Bèges**: Développement du module Noise.