1+ #include < gtest/gtest.h>
2+
3+ #include < MilkdropPreset/MilkdropShader.hpp>
4+
5+ using libprojectM::MilkdropPreset::MilkdropShader;
6+
7+ /* *
8+ * Subclass to expose protected members for testing.
9+ * Provides public wrappers around the protected GetReferencedSamplers()
10+ * method and m_samplerNames member so that test helpers can call them.
11+ */
12+ class MilkdropShaderTestable : public MilkdropShader
13+ {
14+ public:
15+ MilkdropShaderTestable ()
16+ : MilkdropShader(ShaderType::CompositeShader)
17+ {
18+ }
19+
20+ void CallGetReferencedSamplers (const std::string& program)
21+ {
22+ GetReferencedSamplers (program);
23+ }
24+
25+ auto GetSamplerNames () const -> const std::set<std::string>&
26+ {
27+ return m_samplerNames;
28+ }
29+ };
30+
31+ /* *
32+ * Helper: create a testable shader and call GetReferencedSamplers on the given program text.
33+ * Returns the resulting set of sampler names (always includes "main").
34+ */
35+ static auto ParseSamplers (const std::string& program) -> std::set<std::string>
36+ {
37+ MilkdropShaderTestable shader;
38+ shader.CallGetReferencedSamplers (program);
39+ return shader.GetSamplerNames ();
40+ }
41+
42+ // --- Basic positive case ---
43+
44+ TEST (MilkdropShaderSamplerParsing, FindsUncommentedSampler)
45+ {
46+ auto names = ParseSamplers (" uniform sampler2D sampler_mytex;\n " );
47+ EXPECT_TRUE (names.count (" main" ));
48+ EXPECT_TRUE (names.count (" mytex" ));
49+ }
50+
51+ // --- Line comment cases ---
52+
53+ TEST (MilkdropShaderSamplerParsing, IgnoresLineCommentedSampler)
54+ {
55+ auto names = ParseSamplers (" // sampler sampler_rand00;\n " );
56+ EXPECT_TRUE (names.count (" main" ));
57+ EXPECT_FALSE (names.count (" rand00" ))
58+ << " sampler_rand00 inside a // comment should not be extracted" ;
59+ }
60+
61+ TEST (MilkdropShaderSamplerParsing, NoSpaceAfterSlashesStillCommented)
62+ {
63+ // This is the exact pattern from the crash-triggering preset
64+ auto names = ParseSamplers (" //sampler sampler_rand00;\n " );
65+ EXPECT_TRUE (names.count (" main" ));
66+ EXPECT_FALSE (names.count (" rand00" ))
67+ << " sampler_rand00 after //sampler (no space) should not be extracted" ;
68+ }
69+
70+ // --- Block comment cases ---
71+
72+ TEST (MilkdropShaderSamplerParsing, IgnoresBlockCommentedSampler)
73+ {
74+ auto names = ParseSamplers (" /* sampler_rand00 */\n " );
75+ EXPECT_TRUE (names.count (" main" ));
76+ EXPECT_FALSE (names.count (" rand00" ))
77+ << " sampler_rand00 inside /* */ should not be extracted" ;
78+ }
79+
80+ TEST (MilkdropShaderSamplerParsing, BlockCommentSpansMultipleLines)
81+ {
82+ std::string program =
83+ " /*\n "
84+ " sampler_foo;\n "
85+ " texsize_bar;\n "
86+ " */\n "
87+ " uniform sampler2D sampler_real;\n " ;
88+ auto names = ParseSamplers (program);
89+ EXPECT_FALSE (names.count (" foo" ))
90+ << " sampler_foo inside multi-line block comment should not be extracted" ;
91+ EXPECT_FALSE (names.count (" bar" ))
92+ << " texsize_bar inside multi-line block comment should not be extracted" ;
93+ EXPECT_TRUE (names.count (" real" ))
94+ << " sampler_real outside the block comment should be found" ;
95+ }
96+
97+ TEST (MilkdropShaderSamplerParsing, SamplerAfterBlockCommentCloseIsFound)
98+ {
99+ std::string program = " /* comment */ sampler_visible;\n " ;
100+ auto names = ParseSamplers (program);
101+ EXPECT_TRUE (names.count (" visible" ))
102+ << " sampler_visible after a closed block comment should be found" ;
103+ }
104+
105+ // --- texsize comment cases ---
106+
107+ TEST (MilkdropShaderSamplerParsing, IgnoresLineCommentedTexsize)
108+ {
109+ auto names = ParseSamplers (" // texsize_rand00;\n " );
110+ EXPECT_TRUE (names.count (" main" ));
111+ EXPECT_FALSE (names.count (" rand00" ))
112+ << " texsize_rand00 inside // comment should not be extracted" ;
113+ }
114+
115+ TEST (MilkdropShaderSamplerParsing, IgnoresBlockCommentedTexsize)
116+ {
117+ auto names = ParseSamplers (" /* texsize_rand00; */\n " );
118+ EXPECT_TRUE (names.count (" main" ));
119+ EXPECT_FALSE (names.count (" rand00" ))
120+ << " texsize_rand00 inside /* */ should not be extracted" ;
121+ }
122+
123+ // --- Mixed cases ---
124+
125+ TEST (MilkdropShaderSamplerParsing, MixedCommentedAndUncommented)
126+ {
127+ std::string program =
128+ " //sampler sampler_rand00;\n "
129+ " uniform sampler2D sampler_tex1;\n "
130+ " /* sampler_hidden; */\n "
131+ " uniform sampler2D sampler_tex2;\n " ;
132+ auto names = ParseSamplers (program);
133+ EXPECT_FALSE (names.count (" rand00" ))
134+ << " commented sampler_rand00 should be ignored" ;
135+ EXPECT_FALSE (names.count (" hidden" ))
136+ << " block-commented sampler_hidden should be ignored" ;
137+ EXPECT_TRUE (names.count (" tex1" ))
138+ << " uncommented sampler_tex1 should be found" ;
139+ EXPECT_TRUE (names.count (" tex2" ))
140+ << " uncommented sampler_tex2 should be found" ;
141+ }
142+
143+ // --- Edge / special cases ---
144+
145+ TEST (MilkdropShaderSamplerParsing, SkipsSamplerState)
146+ {
147+ auto names = ParseSamplers (" sampler_state { Filter = LINEAR; };\n " );
148+ EXPECT_TRUE (names.count (" main" ));
149+ EXPECT_FALSE (names.count (" state" ))
150+ << " sampler_state is a reserved word and should be skipped" ;
151+ }
152+
153+ TEST (MilkdropShaderSamplerParsing, EmptyProgram)
154+ {
155+ auto names = ParseSamplers (" " );
156+ EXPECT_EQ (names.size (), 1u );
157+ EXPECT_TRUE (names.count (" main" ))
158+ << " Empty program should still contain 'main'" ;
159+ }
160+
161+ TEST (MilkdropShaderSamplerParsing, ReproducesCrashPresetPattern)
162+ {
163+ // This reproduces the exact pattern from the crash-triggering preset line:
164+ // comp_1=`//sampler sampler_rand00; // this will choose a random texture from disk!
165+ // After the backtick is stripped by the preset parser, the shader program
166+ // contains the rest of the line.
167+ std::string program = " //sampler sampler_rand00; // this will choose a random texture from disk!\n " ;
168+ auto names = ParseSamplers (program);
169+ EXPECT_EQ (names.size (), 1u )
170+ << " Only 'main' should be present; the entire line is a comment" ;
171+ EXPECT_TRUE (names.count (" main" ));
172+ EXPECT_FALSE (names.count (" rand00" ))
173+ << " rand00 from the crash-triggering preset comment must not be extracted" ;
174+ }
0 commit comments