Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libprojectM/MilkdropPreset/CustomShape.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class CustomShape

/**
* @brief Compiles all code blocks and runs the init expression.
* @throws MilkdropCompileException Thrown if one of the code blocks couldn't be compiled.
* If one of the code blocks can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
*/
void CompileCodeAndRunInitExpressions();

Expand Down
2 changes: 1 addition & 1 deletion src/libprojectM/MilkdropPreset/CustomWaveform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CustomWaveform

/**
* @brief Compiles all code blocks and runs the init expression.
* @throws MilkdropCompileException Thrown if one of the code blocks couldn't be compiled.
* If one of the code blocks can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param presetPerFrameContext The per-frame context to retrieve the init Q vars from.
*/
void CompileCodeAndRunInitExpressions(const PerFrameContext& presetPerFrameContext);
Expand Down
13 changes: 11 additions & 2 deletions src/libprojectM/MilkdropPreset/PerFrameContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,14 @@ void PerFrameContext::EvaluateInitCode(PresetState& state)
error = "[PerFrameContext] Could not compile per-frame init code.";
}
LOG_DEBUG("[PerFrameContext] Failed per-frame INIT code:\n" + state.perFrameInitCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
for (int q = 0; q < QVarCount; q++)
{
q_values_after_init_code[q] = 0;
state.frameQVariables[q] = 0;
}
return;
}

projectm_eval_code_execute(initCode);
Expand Down Expand Up @@ -260,7 +267,9 @@ void PerFrameContext::CompilePerFrameCode(const std::string& perFrameCode)
error = "[PerFrameContext] Could not compile per-frame code.";
}
LOG_DEBUG("[PerFrameContext] Failed per-frame code:\n" + perFrameCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
return;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/libprojectM/MilkdropPreset/PerFrameContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ class PerFrameContext

/**
* @brief Compiles and runs the preset init code.
* @throws MilkdropCompileException Thrown if the per-frame init code couldn't be compiled.
* If the per-frame init code can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param perFrameInitCode The init code.
*/
void EvaluateInitCode(PresetState& state);

/**
* @brief Compiles the per-frame code and stores the code handle in the class.
* @throws MilkdropCompileException Thrown if the per-frame code couldn't be compiled.
* If the per-frame code can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param perFrameCode The code to compile.
*/
void CompilePerFrameCode(const std::string& perFrameCode);
Expand Down
4 changes: 3 additions & 1 deletion src/libprojectM/MilkdropPreset/PerPixelContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ void PerPixelContext::CompilePerPixelCode(const std::string& perPixelCode)
error = "[PerPixelContext] Could not compile per-pixel code.";
}
LOG_DEBUG("[PerPixelContext] Failed per-pixel code:\n" + perPixelCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
return;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/libprojectM/MilkdropPreset/PerPixelContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class PerPixelContext

/**
* @brief Compiles the per-pixel code and stores the code handle in the class.
* @throws MilkdropCompileException Thrown if the per-pixel code couldn't be compiled.
* If the per-pixel code can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param perPixelCode The code to compile.
*/
void CompilePerPixelCode(const std::string& perPixelCode);
Expand Down
12 changes: 10 additions & 2 deletions src/libprojectM/MilkdropPreset/ShapePerFrameContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,13 @@ void ShapePerFrameContext::EvaluateInitCode(const std::string& perFrameInitCode,
error = "[ShapePerFrameContext] Could not compile custom shape " + std::to_string(shape.m_index) + " per-frame init code.";
}
LOG_DEBUG("[ShapePerFrameContext] Failed custom shape per-frame INIT code:\n" + perFrameInitCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
for (auto* tVar : t_vars)
{
*tVar = 0;
}
return;
}

projectm_eval_code_execute(initCode);
Expand Down Expand Up @@ -195,7 +201,9 @@ void ShapePerFrameContext::CompilePerFrameCode(const std::string& perFrameCode,
error = "[ShapePerFrameContext] Could not compile custom shape " + std::to_string(shape.m_index) + " per-frame code.";
}
LOG_DEBUG("[ShapePerFrameContext] Failed custom shape per-frame code:\n" + perFrameCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
return;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/libprojectM/MilkdropPreset/ShapePerFrameContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ class ShapePerFrameContext

/**
* @brief Compiles and runs the preset init code.
* @throws MilkdropCompileException Thrown if one of the custom shape init code couldn't be compiled.
* If one of the custom shape init code can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param perFrameInitCode The init code.
* @param shape The shape this context belongs to.
*/
void EvaluateInitCode(const std::string& perFrameInitCode, const CustomShape& shape);

/**
* @brief Compiles the per-frame code and stores the code handle in the class.
* @throws MilkdropCompileException Thrown if one of the per-frame code couldn't be compiled.
* If one of the per-frame code can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param perFrameCode The code to compile.
* @param shape The shape this context belongs to.
*/
Expand Down
12 changes: 10 additions & 2 deletions src/libprojectM/MilkdropPreset/WaveformPerFrameContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,13 @@ void WaveformPerFrameContext::EvaluateInitCode(const std::string& perFrameInitCo
error = "[WaveformPerFrameContext] Could not compile custom wave " + std::to_string(waveform.m_index) + " per-frame init code.";
}
LOG_DEBUG("[WaveformPerFrameContext] Failed custom wave per-frame INIT code:\n" + perFrameInitCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
for (auto* tVar : t_vars)
{
*tVar = 0;
}
return;
}

projectm_eval_code_execute(initCode);
Expand Down Expand Up @@ -157,7 +163,9 @@ void WaveformPerFrameContext::CompilePerFrameCode(const std::string& perFrameCod
error = "[WaveformPerFrameContext] Could not compile custom wave " + std::to_string(waveform.m_index) + " per-frame code.";
}
LOG_DEBUG("[WaveformPerFrameContext] Failed custom wave per-frame code:\n" + perFrameCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
return;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/libprojectM/MilkdropPreset/WaveformPerFrameContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ class WaveformPerFrameContext

/**
* @brief Compiles and runs the preset init code.
* @throws MilkdropCompileException Thrown if the custom wave init code couldn't be compiled.
* If the custom wave init code can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param perFrameInitCode The init code.
* @param waveform The waveform this context belongs to.
*/
void EvaluateInitCode(const std::string& perFrameInitCode, CustomWaveform& waveform);

/**
* @brief Compiles the per-frame code and stores the code handle in the class.
* @throws MilkdropCompileException Thrown if the custom wave per-frame code couldn't be compiled.
* If the custom wave per-frame code can't be compiled, a warning is logged and the code is skipped, like in Milkdrop.
* @param perFrameCode The code to compile.
* @param waveform The waveform this context belongs to.
*/
Expand Down
4 changes: 3 additions & 1 deletion src/libprojectM/MilkdropPreset/WaveformPerPointContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ void WaveformPerPointContext::CompilePerPointCode(const std::string& perPointCod
error = "[WaveformPerPointContext] Could not compile custom wave " + std::to_string(waveform.m_index) + " per-point code.";
}
LOG_DEBUG("[WaveformPerPointContext] Failed custom wave " + std::to_string(waveform.m_index) + " per-point code:\n" + perPointCode);
throw MilkdropCompileException(error);
// Like Milkdrop, only this code block is disabled, the preset is still used.
LOG_WARN(error);
return;
}
}

Expand Down
4 changes: 4 additions & 0 deletions tests/libprojectM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ add_executable(projectM-unittest
HLSLParserTest.cpp
HLSLModuloTest.cpp
LoggingTest.cpp
EquationCompileErrorTest.cpp
MilkdropShaderCommentParsingTest.cpp
PCMTest.cpp
PresetFileParserTest.cpp
Expand All @@ -48,6 +49,7 @@ add_executable(projectM-unittest
target_compile_definitions(projectM-unittest
PRIVATE
PROJECTM_TEST_DATA_DIR="${CMAKE_CURRENT_LIST_DIR}/data"
$<TARGET_PROPERTY:projectM::Eval,INTERFACE_COMPILE_DEFINITIONS>
)

# Test includes a header file from libprojectM with its full path in the source dir.
Expand All @@ -56,6 +58,8 @@ target_include_directories(projectM-unittest
"${PROJECTM_SOURCE_DIR}/src/libprojectM"
"${PROJECTM_SOURCE_DIR}"
"${PROJECTM_SOURCE_DIR}/vendor/hlslparser/src"
# For tests using the expression contexts directly.
$<TARGET_PROPERTY:projectM::Eval,INTERFACE_INCLUDE_DIRECTORIES>
)

target_link_libraries(projectM-unittest
Expand Down
57 changes: 57 additions & 0 deletions tests/libprojectM/EquationCompileErrorTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <gtest/gtest.h>

#include <MilkdropPreset/PerFrameContext.hpp>

#include <projectm-eval.h>

using libprojectM::MilkdropPreset::PerFrameContext;

namespace {

/**
* PresetState needs an OpenGL context, so the expression context is set up with its own memory here.
*/
class EquationCompileErrorTest : public testing::Test
{
protected:
void SetUp() override
{
memory = projectm_eval_memory_buffer_create();
context = std::make_unique<PerFrameContext>(memory, &registers);
context->RegisterBuiltinVariables();
}

void TearDown() override
{
context.reset();
projectm_eval_memory_buffer_destroy(memory);
}

projectm_eval_mem_buffer memory{};
PRJM_EVAL_F registers[100]{};
std::unique_ptr<PerFrameContext> context;
};

} // namespace

/**
* Like Milkdrop, a code block that can't be compiled is skipped, and the rest of the preset is still used.
*/
TEST_F(EquationCompileErrorTest, InvalidPerFrameCodeIsSkipped)
{
// "0.99l" isn't a valid number, so this doesn't compile.
EXPECT_NO_THROW(context->CompilePerFrameCode("additive = above(sin(time * 200), 0.99l);"));
EXPECT_EQ(context->perFrameCodeHandle, nullptr);

// Executing the skipped code does nothing.
EXPECT_NO_THROW(context->ExecutePerFrameCode());
}

TEST_F(EquationCompileErrorTest, ValidPerFrameCodeIsCompiledAndExecuted)
{
context->CompilePerFrameCode("zoom = 1.25;");
ASSERT_NE(context->perFrameCodeHandle, nullptr);

context->ExecutePerFrameCode();
EXPECT_EQ(*context->zoom, 1.25);
}