GCC Code Coverage Report


Directory: ./
File: FPPLocale.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 37 51 72.5%
Functions: 4 6 66.7%
Branches: 71 146 48.6%

Line Branch Exec Source
1 /*
2 * This file is part of the Falcon Player (FPP) and is Copyright (C)
3 * 2013-2022 by the Falcon Player Developers.
4 *
5 * The Falcon Player (FPP) is free software, and is covered under
6 * multiple Open Source licenses. Please see the included 'LICENSES'
7 * file for descriptions of what files are covered by each license.
8 *
9 * This source file is covered under the LGPL v2.1 as described in the
10 * included LICENSE.LGPL file.
11 */
12
13 #include "fpp-pch.h"
14
15 #include "fpp-json.h"
16
17 #include <sys/stat.h>
18
19 #include "common.h"
20 #include "settings.h"
21 #include "commands/Commands.h"
22
23 #include "FPPLocale.h"
24
25 Json::Value LocaleHolder::locale;
26 std::mutex LocaleHolder::localeLock;
27 std::string LocaleHolder::localeKey;
28
29 // The cache is rebuilt whenever what it was built from changes, whoever
30 // changed it: the holiday editor writes user-holidays.json through the
31 // config file API, and Locale can change from the UI, an upload or a
32 // restored backup. Only clearing it on request left fppd scheduling with the
33 // old holidays until it restarted.
34 43813 static std::string LocaleSourceKey(const std::string& localeName, const std::string& userHolidaysFile) {
35
1/2
✓ Branch 0 taken 43813 times.
✗ Branch 1 not taken.
43813 std::string key = localeName;
36 struct stat st;
37
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 43811 times.
43813 if (stat(userHolidaysFile.c_str(), &st) == 0) {
38 #ifdef PLATFORM_OSX
39 const struct timespec& mt = st.st_mtimespec;
40 #else
41 2 const struct timespec& mt = st.st_mtim;
42 #endif
43
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 key += "|" + std::to_string((long long)st.st_size) + "|" +
44
6/12
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
6 std::to_string((long long)mt.tv_sec) + "." + std::to_string((long long)mt.tv_nsec);
45 }
46 43813 return key;
47 ✗ }
48
49 43813 Json::Value LocaleHolder::GetLocale() {
50
1/2
✓ Branch 0 taken 43813 times.
✗ Branch 1 not taken.
43813 std::unique_lock<std::mutex> lock(localeLock);
51
52
1/2
✓ Branch 0 taken 43813 times.
✗ Branch 1 not taken.
43813 std::string localeName = getSetting("Locale");
53
54
2/4
✓ Branch 0 taken 43813 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43813 times.
43813 if (localeName == "")
55 ✗ localeName = "Global";
56
57
3/6
✓ Branch 0 taken 43813 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43813 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43813 times.
✗ Branch 5 not taken.
43813 std::string userHolidaysFile = FPP_DIR_CONFIG("/user-holidays.json");
58
1/2
✓ Branch 0 taken 43813 times.
✗ Branch 1 not taken.
43813 std::string key = LocaleSourceKey(localeName, userHolidaysFile);
59
7/8
✓ Branch 0 taken 43813 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43754 times.
✓ Branch 3 taken 59 times.
✓ Branch 4 taken 43752 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 43752 times.
✓ Branch 7 taken 61 times.
43813 if (locale.size() && key == localeKey)
60
1/2
✓ Branch 0 taken 43752 times.
✗ Branch 1 not taken.
43752 return locale;
61
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 locale.clear();
62
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 localeKey = key;
63
64 // From fppd's own tree, not /opt/fpp: an install anywhere else (macOS, a
65 // test tree) found no locale file, so every holiday name in the schedule
66 // was unknown.
67
3/6
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
61 std::string localeFile = getFPPDDir("/etc/locale/" + localeName + ".json");
68
69
2/4
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 61 times.
61 if (!FileExists(localeFile)) {
70 ✗ localeFile = getFPPDDir("/etc/locale/Global.json");
71 }
72
73
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 bool result = LoadJsonFromFile(localeFile, locale, JsonRoot::Object);
74
75
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 if (result) {
76 // Load user-defined holidays and merge them with locale holidays
77
3/4
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 60 times.
61 if (FileExists(userHolidaysFile)) {
78
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Json::Value userHolidays;
79
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (LoadJsonFromFile(userHolidaysFile, userHolidays, JsonRoot::Array)) {
80
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 if (userHolidays.isArray() && userHolidays.size() > 0) {
81 // Ensure the locale has a holidays array
82
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!locale.isMember("holidays")) {
83 ✗ locale["holidays"] = Json::Value(Json::arrayValue);
84 }
85
86 // Append user-defined holidays to the locale holidays
87
3/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 for (Json::ArrayIndex i = 0; i < userHolidays.size(); i++) {
88
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 locale["holidays"].append(userHolidays[i]);
89 }
90 }
91 }
92 1 }
93
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 return locale;
94 }
95
96 ✗ Json::Value empty;
97
98 ✗ return empty;
99 43813 }
100
101 ✗ void LocaleHolder::ClearCache() {
102 ✗ std::unique_lock<std::mutex> lock(localeLock);
103 ✗ locale.clear();
104 ✗ localeKey.clear();
105 ✗ }
106
107 /**********************************************************************/
108 // Command to clear the locale cache
109 class ClearLocaleCacheCommand : public Command {
110 public:
111
2/4
✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
3774 ClearLocaleCacheCommand() : Command("Clear Locale Cache") {
112
6/12
✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1887 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1887 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1887 times.
✗ Branch 11 not taken.
11322 args.push_back(CommandArg("force", "bool", "Force Clear").setDefaultValue("true"));
113 1887 }
114
115 ✗ virtual std::unique_ptr<Command::Result> run(const std::vector<std::string>& args) override {
116 ✗ LocaleHolder::ClearCache();
117 ✗ return std::make_unique<Command::Result>("Locale cache cleared");
118 }
119 };
120
121 1887 void LocaleHolder::RegisterCommands() {
122
6/12
✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1727 times.
✓ Branch 7 taken 160 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1727 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2207 CommandManager::INSTANCE.addCategorizedCommand(new ClearLocaleCacheCommand(), "System", 3);
123 1887 }
124