• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / score / 32923660642

26 Aug 2026 02:40AM UTC coverage: 23.574% (+0.4%) from 23.21%
32923660642

push

github

jcelerier
gfx: add missing guards on message processing for texture / buffer / geometry

0 of 6 new or added lines in 1 file covered. (0.0%)

4413 existing lines in 83 files now uncovered.

53181 of 225592 relevant lines covered (23.57%)

61000.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.17
/src/plugins/score-plugin-js/JS/ApplicationPlugin.cpp
1
#include "ApplicationPlugin.hpp"
2

3
#include <JS/DocumentPlugin.hpp>
4
#include <JS/Qml/DeviceContext.hpp>
5
#include <JS/Qml/EditContext.hpp>
6
#include <JS/Qml/Utils.hpp>
7
#include <JS/Qml/ViewContext.hpp>
8
#include <Library/LibrarySettings.hpp>
9
#include <LocalTree/LocalTreeDocumentPlugin.hpp>
10

11
#include <core/application/ApplicationInterface.hpp>
12
#include <core/document/Document.hpp>
13
#include <core/presenter/DocumentManager.hpp>
14

15
#include <ossia/detail/thread.hpp>
16

17
#include <ossia-qt/invoke.hpp>
18
#include <ossia-qt/qml_protocols.hpp>
19

20
#include <QCommandLineParser>
21
#include <QFile>
22
#include <QFileInfo>
23

24
#if __has_include(<QQuickWindow>)
25
#include <QGuiApplication>
26
#include <QQuickItem>
27
#include <QQuickWindow>
28
#endif
29

30
#if SCORE_HAS_GPU_JS
31
#include <Gfx/Settings/Model.hpp>
32
#endif
33

34
#include <ossia/network/context.hpp>
35

36
namespace JS
37
{
38
// Whether --script was given a program or the path of one. An existing file is
39
// always a path; anything with JS punctuation in it is a program.
40
static bool stringIsScript(const QString& input)
262✔
41
{
42
  if(input.isEmpty())
262✔
43
    return false;
256✔
44

45
  if(QFileInfo fileInfo{input}; fileInfo.exists() && fileInfo.isFile())
10✔
46
    return false;
4✔
47

48
  if(input.length() > 4096)
2✔
UNCOV
49
    return true;
×
50

51
  for(QChar ch : input)
38✔
52
  {
53
    const char16_t c = ch.unicode();
37✔
54
    if(c == '\n' || c == '\r' || c == ';' || c == '{' || c == '}' || c == '('
37✔
55
       || c == ')')
37✔
56
      return true;
1✔
57
  }
58

59
  return false;
1✔
60
}
262✔
61

62
ApplicationPlugin::ApplicationPlugin(const score::GUIApplicationContext& ctx)
262✔
63
    : score::GUIApplicationPlugin{ctx}
262✔
64
{
262✔
65
#if __has_include(<QQuickWindow>)
66
  // Crisp text in every QML UI: distance-field rendering looks blurry at the small
67
  // font sizes our panels use, native glyph rendering matches the rest of score.
68
  QQuickWindow::setTextRenderType(QQuickWindow::NativeTextRendering);
262✔
69
#endif
70

71
  // For the console
72
  m_consoleEngine.globalObject().setProperty("Score", m_consoleEngine.newQObject(new EditJsContext));
262✔
73
  m_consoleEngine.globalObject().setProperty("Util", m_consoleEngine.newQObject(new JsUtils));
262✔
74
  m_consoleEngine.globalObject().setProperty(
524✔
75
      "System", m_consoleEngine.newQObject(new JsSystem));
262✔
76
  m_consoleEngine.globalObject().setProperty(
524✔
77
      "Library", m_consoleEngine.newQObject(new JsLibrary));
262✔
78
  m_consoleEngine.globalObject().setProperty("Device", m_consoleEngine.newQObject(new DeviceContext{m_consoleEngine}));
262✔
79
  m_consoleEngine.globalObject().setProperty("View", m_consoleEngine.newQObject(new JsViewContext));
262✔
80
  connect(&m_consoleEngine, &QQmlEngine::exit, this, [&](int retCode) {
266✔
81
    for(auto& doc : score::GUIAppContext().docManager.documents())
8✔
82
      doc->commandStack().markCurrentIndexAsSaved();
4✔
83
    // quit() is exit(0), which discarded the code Qt.exit() was given: a script
84
    // could stop the app but never report that it had failed.
85
    qApp->exit(retCode);
4✔
86
    QTimer::singleShot(
4✔
UNCOV
87
        500, [] { score::GUIApplicationInterface::instance().forceExit(); });
×
88
  });
4✔
89
  m_asioContext = std::make_shared<ossia::net::network_context>();
262✔
90
  m_processMessages = true;
262✔
91
  m_consoleEngine.globalObject().setProperty(
524✔
92
      "Protocols",
262✔
93
      m_consoleEngine.newQObject(new ossia::qt::qml_protocols{m_asioContext, this}));
262✔
94
  m_asioThread = std::thread{[this] {
524✔
95
    ossia::set_thread_name("ossia app asio");
262✔
96
    while(m_processMessages)
524✔
97
    {
98
      m_asioContext->run();
262✔
99
    }
100
  }};
262✔
101

102
  // For scripts of processes that run in the ui thread:
103
  m_scriptProcessUIEngine.globalObject().setProperty(
524✔
104
      "Util", m_scriptProcessUIEngine.newQObject(new JsUtils));
262✔
105
  m_scriptProcessUIEngine.globalObject().setProperty(
524✔
106
      "System", m_scriptProcessUIEngine.newQObject(new JsSystem));
262✔
107
  m_scriptProcessUIEngine.globalObject().setProperty(
524✔
108
      "Library", m_scriptProcessUIEngine.newQObject(new JsLibrary));
262✔
109
  m_scriptProcessUIEngine.globalObject().setProperty(
524✔
110
      "View", m_scriptProcessUIEngine.newQObject(new JsViewContext));
262✔
111

112
  // Command-line option parsing
113
  QCommandLineParser parser;
262✔
114

115
  QCommandLineOption script_opt(
262✔
116
      "script", QCoreApplication::translate("js", "script"), "Script", "");
262✔
117
  parser.addOption(script_opt);
262✔
118

119
  parser.parse(ctx.applicationSettings.arguments);
262✔
120
  const auto script = parser.value(script_opt);
262✔
121
  if(stringIsScript(script))
262✔
122
  {
123
    this->m_start_script = script;
1✔
124
  }
1✔
125
  else if(!script.isEmpty())
261✔
126
  {
127
    QFile f{script};
5✔
128
    if(f.open(QIODevice::ReadOnly))
5✔
129
    {
130
      this->m_start_script = f.readAll();
4✔
131
      this->m_start_script_name = script;
4✔
132
      this->m_start_script_path = QFileInfo{f}.canonicalPath();
4✔
133
    }
4✔
134
    else
135
    {
136
      qCritical() << "--script: cannot open" << script << ":" << f.errorString();
1✔
137
      this->m_start_script_failed = true;
1✔
138
    }
139
  }
5✔
140
}
×
141

142
void ApplicationPlugin::on_newDocument(score::Document& doc)
152✔
143
{
144
  score::addDocumentPlugin<DocumentPlugin>(doc);
152✔
145
}
152✔
146

147
ApplicationPlugin::~ApplicationPlugin()
522✔
148
{
261✔
149
  m_processMessages = false;
261✔
150
  m_asioContext->context.stop();
261✔
151
  m_asioThread.join();
261✔
152
}
522✔
153

154
void ApplicationPlugin::on_createdDocument(score::Document& doc)
161✔
155
{
156
  // Local Tree
157
  LocalTree::DocumentPlugin* lt = doc.context().findPlugin<LocalTree::DocumentPlugin>();
161✔
158
  if(lt)
161✔
159
  {
160
    auto& root = lt->device().get_root_node();
161✔
161

162
    auto node = root.create_child("script");
161✔
163
    auto address = node->create_parameter(ossia::val_type::STRING);
161✔
164
    address->set_value(std::string{});
161✔
165
    address->set_access(ossia::access_mode::SET);
161✔
166
    address->add_callback([&](const ossia::value& v) {
161✔
167
      ossia::qt::run_async(
×
UNCOV
168
          this, [this, str = QString::fromStdString(ossia::convert<std::string>(v))] {
×
UNCOV
169
        auto res = m_consoleEngine.evaluate(str);
×
UNCOV
170
        if(res.isError())
×
171
        {
UNCOV
172
          qDebug() << res.toString();
×
UNCOV
173
        }
×
UNCOV
174
      });
×
175
    });
×
176
  }
161✔
177

178
  // Custom data
179
  if(auto customData = doc.context().findPlugin<DocumentPlugin>(); !customData)
161✔
UNCOV
180
    score::addDocumentPlugin<DocumentPlugin>(doc);
×
181

182
  if(m_start_script_failed)
161✔
183
  {
184
    qGuiApp->exit(2);
1✔
185
    return;
1✔
186
  }
187

188
  if(!m_start_script.isEmpty())
160✔
189
  {
190
    QTimer::singleShot(100, this, [this] {
10✔
191
      if(!m_start_script_path.isEmpty())
5✔
192
        m_consoleEngine.addImportPath(m_start_script_path);
4✔
193

194
      // Report a throwing --script: an unresolvable readFile returns an empty
195
      // string and eval("") is a no-op, so the process would otherwise exit
196
      // reporting success and a harness could not tell that from a pass.
197
      const auto res = m_consoleEngine.evaluate(m_start_script, m_start_script_name);
5✔
198
      if(res.isError())
5✔
199
      {
200
        qCritical().noquote()
2✔
201
            << "--script:"
1✔
202
            << (m_start_script_name.isEmpty() ? QStringLiteral("<inline>")
1✔
203
                                              : m_start_script_name)
1✔
204
            << "line" << res.property("lineNumber").toInt() << ":" << res.toString();
1✔
205
        qGuiApp->exit(3);
1✔
206
      }
1✔
207
    });
5✔
208
  }
5✔
209
}
161✔
210
void ApplicationPlugin::afterStartup()
6✔
211
{
212
  // Dummy engine setup for JS processes
213
  // eng.importModule(
214
  //     "/home/jcelerier/Documents/ossia/score/packages/default/Scripts/include/"
215
  //     "tonal.mjs");
216
  for(auto& p : this->context.settings<Library::Settings::Model>().getIncludePaths())
6✔
217
  {
UNCOV
218
    m_scriptProcessUIEngine.addImportPath(p);
×
219
  }
220

221
#if __has_include(<QQuickWindow>)
222
  if(QFileInfo f{context.applicationSettings.ui}; f.isFile())
6✔
223
  {
UNCOV
224
    m_comp = new QQmlComponent{&m_consoleEngine, f.absoluteFilePath(), this};
×
225

UNCOV
226
    if(auto obj = m_comp->create())
×
227
    {
UNCOV
228
      if(auto item = qobject_cast<QQuickItem*>(obj))
×
229
      {
UNCOV
230
        m_window = new QQuickWindow{};
×
231
  // QWidget gets these from QWidgetPrivate::adjustFlags; a bare QQuickWindow
232
  // does not, and on platforms where Qt draws the chrome itself (wasm) that
233
  // leaves the window with no title bar, close or minimise button.
UNCOV
234
  m_window->setFlags(
×
UNCOV
235
      m_window->flags() | Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint
×
UNCOV
236
      | Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint
×
UNCOV
237
      | Qt::WindowMaximizeButtonHint);
×
238
#if defined(__EMSCRIPTEN__)
239
  // Qt for wasm reports ShowIsFullScreen unconditionally, so QWindow::show()
240
  // turns into showFullScreen() for every top level: the requested size is
241
  // discarded and the full-screen state suppresses the frame. Only Qt::Dialog
242
  // and Qt::Popup opt out (QWasmIntegration::defaultWindowState).
243
  m_window->setFlags(m_window->flags() | Qt::Dialog);
244
#endif
UNCOV
245
        m_window->setWidth(640);
×
UNCOV
246
        m_window->setHeight(480);
×
UNCOV
247
        item->setParentItem(m_window->contentItem());
×
248
#if defined(__EMSCRIPTEN__)
249
        m_window->showNormal();
250
#else
UNCOV
251
        m_window->show();
×
252
#endif
UNCOV
253
        return;
×
254
      }
UNCOV
255
    }
×
256
    else
257
    {
UNCOV
258
      qDebug() << m_comp->errorString();
×
UNCOV
259
      qGuiApp->exit(1);
×
260
    }
UNCOV
261
    delete m_comp;
×
UNCOV
262
  }
×
263
#endif
264
}
6✔
265
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc