3535
3636#include < nlohmann/json.hpp>
3737
38+ #include < cstdio>
39+
40+ #ifndef _WIN32
41+ #include < unistd.h>
42+ #include < fcntl.h>
43+ #else
44+ #include < io.h>
45+ #endif
46+
3847using namespace vix ::cli::style;
3948namespace fs = std::filesystem;
4049
@@ -65,6 +74,124 @@ namespace
6574 return false ;
6675 }
6776
77+ struct ScopedSilenceStdStreams
78+ {
79+ bool active{false };
80+
81+ #ifndef _WIN32
82+ int savedStdout{-1 };
83+ int savedStderr{-1 };
84+ int nullFd{-1 };
85+ #else
86+ int savedStdout{-1 };
87+ int savedStderr{-1 };
88+ int nullFd{-1 };
89+ #endif
90+
91+ ScopedSilenceStdStreams ()
92+ {
93+ std::fflush (stdout);
94+ std::fflush (stderr);
95+
96+ #ifndef _WIN32
97+ nullFd = ::open (" /dev/null" , O_WRONLY);
98+ if (nullFd == -1 )
99+ return ;
100+
101+ savedStdout = ::dup (STDOUT_FILENO);
102+ savedStderr = ::dup (STDERR_FILENO);
103+
104+ if (savedStdout == -1 || savedStderr == -1 )
105+ {
106+ if (savedStdout != -1 )
107+ ::close (savedStdout);
108+ if (savedStderr != -1 )
109+ ::close (savedStderr);
110+ ::close (nullFd);
111+ savedStdout = -1 ;
112+ savedStderr = -1 ;
113+ nullFd = -1 ;
114+ return ;
115+ }
116+
117+ if (::dup2 (nullFd, STDOUT_FILENO) == -1 ||
118+ ::dup2 (nullFd, STDERR_FILENO) == -1)
119+ {
120+ ::dup2 (savedStdout, STDOUT_FILENO);
121+ ::dup2 (savedStderr, STDERR_FILENO);
122+ ::close (savedStdout);
123+ ::close (savedStderr);
124+ ::close (nullFd);
125+ savedStdout = -1 ;
126+ savedStderr = -1 ;
127+ nullFd = -1 ;
128+ return ;
129+ }
130+
131+ active = true ;
132+ #else
133+ nullFd = _open (" NUL" , _O_WRONLY);
134+ if (nullFd == -1 )
135+ return ;
136+
137+ savedStdout = _dup (_fileno (stdout));
138+ savedStderr = _dup (_fileno (stderr));
139+
140+ if (savedStdout == -1 || savedStderr == -1 )
141+ {
142+ if (savedStdout != -1 )
143+ _close (savedStdout);
144+ if (savedStderr != -1 )
145+ _close (savedStderr);
146+ _close (nullFd);
147+ savedStdout = -1 ;
148+ savedStderr = -1 ;
149+ nullFd = -1 ;
150+ return ;
151+ }
152+
153+ if (_dup2 (nullFd, _fileno (stdout)) == -1 ||
154+ _dup2 (nullFd, _fileno (stderr)) == -1 )
155+ {
156+ _dup2 (savedStdout, _fileno (stdout));
157+ _dup2 (savedStderr, _fileno (stderr));
158+ _close (savedStdout);
159+ _close (savedStderr);
160+ _close (nullFd);
161+ savedStdout = -1 ;
162+ savedStderr = -1 ;
163+ nullFd = -1 ;
164+ return ;
165+ }
166+
167+ active = true ;
168+ #endif
169+ }
170+
171+ ~ScopedSilenceStdStreams ()
172+ {
173+ if (!active)
174+ return ;
175+
176+ std::fflush (stdout);
177+ std::fflush (stderr);
178+
179+ #ifndef _WIN32
180+ ::dup2 (savedStdout, STDOUT_FILENO);
181+ ::dup2 (savedStderr, STDERR_FILENO);
182+ ::close (savedStdout);
183+ ::close (savedStderr);
184+ ::close (nullFd);
185+ #else
186+ _dup2 (savedStdout, _fileno (stdout));
187+ _dup2 (savedStderr, _fileno (stderr));
188+ _close (savedStdout);
189+ _close (savedStderr);
190+ _close (nullFd);
191+ #endif
192+ }
193+ };
194+
68195 static bool is_watched_file (const fs::path &p)
69196 {
70197 const auto ext = p.extension ().string ();
@@ -363,12 +490,18 @@ namespace
363490 return vix::cli::process::normalize_exit_code (raw);
364491 }
365492
493+ static std::string project_name_from_dir (const fs::path &projectDir)
494+ {
495+ std::string name = projectDir.filename ().string ();
496+ if (name.empty ())
497+ name = " app" ;
498+ return name;
499+ }
500+
366501 static int ensure_project_configured_and_built (
367502 const vix::commands::TestsCommand::detail::Options &opt,
368503 const std::string &presetName)
369504 {
370- info (" Tests are not ready. Auto-configure/auto-build via `vix check`." );
371-
372505 std::vector<std::string> forwarded = opt.forwarded ;
373506
374507 if (!has_flag (forwarded, " --tests" ))
@@ -381,6 +514,30 @@ namespace
381514 forwarded.push_back (presetName);
382515 }
383516
517+ const std::string projectName = project_name_from_dir (opt.projectDir );
518+ const std::string testFlag = " -D" + projectName + " _BUILD_TESTS=ON" ;
519+
520+ bool hasDashDash = false ;
521+ bool hasTestFlag = false ;
522+
523+ for (const auto &arg : forwarded)
524+ {
525+ if (arg == " --" )
526+ hasDashDash = true ;
527+
528+ if (arg == testFlag)
529+ hasTestFlag = true ;
530+ }
531+
532+ if (!hasTestFlag)
533+ {
534+ if (!hasDashDash)
535+ forwarded.push_back (" --" );
536+
537+ forwarded.push_back (testFlag);
538+ }
539+
540+ ScopedSilenceStdStreams silence;
384541 return vix::commands::CheckCommand::run (forwarded);
385542 }
386543
@@ -567,17 +724,7 @@ namespace
567724 const auto runner = find_native_test_runner (refreshedBuildDir);
568725
569726 if (!runner)
570- {
571- error (" Native test runner not found." );
572- hint (" Expected a built test executable from the project or umbrella." );
573- step (std::string (" Build dir: " ) + refreshedBuildDir.string ());
574727 return 2 ;
575- }
576-
577- info (" Running tests (native runner)." );
578- hint (std::string (" Preset: " ) + presetName);
579- hint (std::string (" Build dir: " ) + refreshedBuildDir.string ());
580- hint (std::string (" Runner: " ) + runner->string ());
581728
582729 std::vector<std::string> argv;
583730 argv.push_back (runner->string ());
@@ -609,16 +756,11 @@ namespace
609756
610757 if (!ctest_file_exists (refreshedBuildDir))
611758 {
612- error (" CTest metadata is not available." );
613- hint (" Tests may be disabled in the project or no CTest entries were generated." );
614- step (std::string (" Expected file: " ) + (refreshedBuildDir / " CTestTestfile.cmake" ).string ());
759+ error (" No tests available." );
760+ hint (" Tests are disabled for this project in the current CMake configuration." );
615761 return 1 ;
616762 }
617763
618- info (" Running tests (CTest fallback)." );
619- hint (std::string (" Preset: " ) + presetName);
620- hint (std::string (" Build dir: " ) + refreshedBuildDir.string ());
621-
622764 std::vector<std::string> argv;
623765 argv.push_back (" ctest" );
624766
@@ -640,10 +782,8 @@ namespace
640782 if (nativeCode != 2 )
641783 return nativeCode;
642784
643- info (" Falling back to CTest." );
644785 return run_ctest (opt);
645786 }
646-
647787} // namespace
648788
649789namespace vix ::commands::TestsCommand
0 commit comments