File: script_test_fixture.h

package info (click to toggle)
gerbera 2.4.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 15,412 kB
  • sloc: cpp: 44,738; javascript: 13,430; xml: 5,730; ansic: 2,692; sh: 1,555; sql: 237; python: 191; makefile: 13
file content (233 lines) | stat: -rw-r--r-- 9,060 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*GRB*

    Gerbera - https://gerbera.io/

    script_test_fixture.h - this file is part of Gerbera.

    Copyright (C) 2020-2025 Gerbera Contributors

    Gerbera is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2
    as published by the Free Software Foundation.

    Gerbera is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Gerbera.  If not, see <http://www.gnu.org/licenses/>.

    $Id$
*/
#ifdef HAVE_JS
#ifndef GERBERA_SCRIPTTESTFIXTURE_H
#define GERBERA_SCRIPTTESTFIXTURE_H

#include "util/string_converter.h"

#include "common_script_mock.h"

#include <duktape.h>
#include <gtest/gtest.h>
#include <memory>
#include <tuple>

using namespace ::testing;

struct addCdsObjectParams {
    std::map<std::string, std::string> objectValues;
    std::string containerChain;
    std::string objectType;
};

struct boxConfig {
    std::string key;
    std::string title;
    std::string upnpClass;
    bool enabled;
    int size;
};

struct abcBoxParams {
    std::string inputValue;
    int boxType;
    std::string divChar;
};

struct getRootPathParams {
    std::string objScriptPath;
    std::string origObjLocation;
};

struct copyObjectParams {
    bool isObject;
};

struct getCdsObjectParams {
    std::string location;
};

// The class provides a way to test the Duktape scripts
// providing various c++ translations of script functions
// useful for mocking said functions with expectations.
class ScriptTestFixture : public ::testing::Test {
    // Loads common.js if running test for another script
    void loadCommon(duk_context* ctx) const;

public:
    // Builds up the Duktape context
    // Reads in the script under test
    void SetUp() override;

    // Destroys the Duktape context
    void TearDown() override;

    // Creates a mock item(orig) global object in Duktape context
    static duk_ret_t dukMockItem(duk_context* ctx, const std::string& mimetype, const std::string& id, int theora, const std::string& title,
        const std::vector<std::pair<std::string, std::string>>& meta, const std::map<std::string, std::string>& aux, const std::map<std::string, std::string>& res,
        const std::string& location, int onlineService);
    static void dukMockItem(duk_context* ctx, const std::map<std::string, std::string>& props,
        const std::vector<std::pair<std::string, std::string>>& meta, const std::map<std::string, std::string>& aux, const std::map<std::string, std::string>& res);

    // Load playlist file from fixtures
    static void mockPlaylistFile(const std::string& mockFile);

    // Creates a mock metafile global object in Duktape context
    duk_ret_t dukMockMetafile(duk_context* ctx, const std::string& location, const std::string& fileName);
    static void dukMockMetafile(duk_context* ctx, const std::map<std::string, std::string>& props);

    // Creates a mock playlist global object in Duktape context
    duk_ret_t dukMockPlaylist(duk_context* ctx, const std::string& title, const std::string& location, const std::string& mimetype);
    static void dukMockPlaylist(duk_context* ctx, const std::map<std::string, std::string>& props);

    // Add global Duktape methods to proxy into c++ layer
    void addGlobalFunctions(duk_context* ctx, const duk_function_list_entry* funcs, const std::map<std::string_view, std::string_view>& config = {}, const std::vector<boxConfig>& boxDefaults = {});

    // Add config entries to global context
    static void addConfig(duk_context* ctx, const std::map<std::string_view, std::string_view>& config, const std::vector<boxConfig>& boxDefaults = {});

    // Access the global object(script) by name, and execute
    void executeScript(duk_context* ctx);
    void callFunction(duk_context* ctx, void(dukMockFunction)(duk_context* ctx, const std::map<std::string, std::string>& props), const std::map<std::string, std::string>& props, const std::string& rootPath = "");

    // Proxy the common.js script with `createContainerChain`
    // Mimics the creation of a directory chain
    // Returns the chain as a vector of strings (for easy expectations)
    static std::vector<std::string> createContainerChain(duk_context* ctx);

    // Proxy the common.js script with `getLastPath`
    // Mimics finding the last path of the item
    // Pushes the last path value to the Duktape stack
    // Returns the inputPath parameter sent by the script
    static std::pair<std::string, int> getLastPath2(duk_context* ctx);
    static std::string getLastPath(duk_context* ctx);

    // Proxy the common.js script with `getPlaylistType`
    // Mimics determination of the playlist type
    // Pushes the playlist type `m3u`, `pls` to the duktape stack
    // Returns the input parameter matching the mimetype
    // sent by the script
    static std::string getPlaylistType(duk_context* ctx);

    // Proxy the common.js script with `print`
    // Mimics the print of text
    // Returns the string sent by the script to print
    static std::string print(duk_context* ctx);
    static std::tuple<std::string, std::string> print2(duk_context* ctx);

    // Proxy the common.js script with `getYear`
    // Mimics the parsing of YYYY
    // Pushes the year in YYYY format to the duktape context
    // Returns the full date sent by the script
    static std::string getYear(duk_context* ctx);

    // Proxy the Duktape script with `addCdsObject` global function.
    // Translates the Duktape value stack to c++
    static addCdsObjectParams addCdsObject(duk_context* ctx, const std::vector<std::string>& objectKeys);

    // Proxy the Duktape script with `addContainerTree` C function.
    // Translates the Duktape value stack to c++
    static std::vector<std::string> addContainerTree(duk_context* ctx, std::map<std::string, std::string> resMap);

    // Proxy the Duktape script with `abcbox` common.js function
    static abcBoxParams abcBox(duk_context* ctx);

    // Proxy the Duktape script with `getRootPath` common.js function
    static getRootPathParams getRootPath(duk_context* ctx);

    // Proxy the Duktape script with `copyObject` global function
    static copyObjectParams copyObject(duk_context* ctx, const std::map<std::string, std::string>& obj, const std::map<std::string, std::string>& meta);

    // Proxy the Duktape script with `copyObject` global function
    static getCdsObjectParams getCdsObject(duk_context* ctx, const std::map<std::string, std::string>& obj, const std::map<std::string, std::string>& meta);

    // Script file name under test
    // System defaults to known project path `/scripts/js/<scriptName>`
    std::string scriptName;
    std::string functionName;
    std::string objectName = "obj";
    // Select audio layout to test
    std::string audioLayout;

    // Used to iterate through `readln` content
    static int readLineCnt;
    static std::vector<std::string> lines;

    // The Duktape Context
    duk_context* ctx;
};

class CommonScriptTestFixture : public ScriptTestFixture {
public:
    // As Duktape requires static methods, so must the mock expectations be
    static std::unique_ptr<CommonScriptMock> commonScriptMock;

    CommonScriptTestFixture()
    {
        commonScriptMock = std::make_unique<::testing::NiceMock<CommonScriptMock>>();
    }

    ~CommonScriptTestFixture() override
    {
        commonScriptMock.reset();
    }

    static inline duk_ret_t js_print(duk_context* ctx)
    {
        std::string msg = ScriptTestFixture::print(ctx);
        return CommonScriptTestFixture::commonScriptMock->print(msg);
    }

    static inline duk_ret_t js_print2(duk_context* ctx)
    {
        auto [mode, msg] = ScriptTestFixture::print2(ctx);
        return CommonScriptTestFixture::commonScriptMock->print2(mode, msg);
    }

    static inline duk_ret_t js_getPlaylistType(duk_context* ctx)
    {
        std::string playlistMimeType = ScriptTestFixture::getPlaylistType(ctx);
        return CommonScriptTestFixture::commonScriptMock->getPlaylistType(playlistMimeType);
    }

    static inline duk_ret_t js_createContainerChain(duk_context* ctx)
    {
       std::vector<std::string> array = ScriptTestFixture::createContainerChain(ctx);
       return CommonScriptTestFixture::commonScriptMock->createContainerChain(array);
    }

    static inline duk_ret_t js_getLastPath(duk_context* ctx)
    {
        std::string inputPath = ScriptTestFixture::getLastPath(ctx);
        return CommonScriptTestFixture::commonScriptMock->getLastPath(inputPath);
    }

    static inline duk_ret_t js_getLastPath2(duk_context* ctx)
    {
        auto [inputPath, length] = ScriptTestFixture::getLastPath2(ctx);
        return CommonScriptTestFixture::commonScriptMock->getLastPath2(inputPath, length);
    }
};
#endif //GERBERA_SCRIPTTESTFIXTURE_H
#endif //HAVE_JS