Repository navigation
Expand file tree
/
Copy pathtest_execution_context_resolver.cpp
More file actions
137 lines (119 loc) · 5.44 KB
/
Copy pathtest_execution_context_resolver.cpp
File metadata and controls
137 lines (119 loc) · 5.44 KB
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
/*
* This file is part of Notepad Next.
* Copyright 2026 NotepadAI contributors
*
* Notepad Next is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Notepad Next 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 Notepad Next. If not, see <https://www.gnu.org/licenses/>.
*/
#include <QtTest>
#include <QDir>
#include "TerminalCwdResolver.h"
#include "remote/ExecutionContext.h"
#include "remote/LocalExecutionContext.h"
using namespace remote;
// Minimal fake remote context: isRemote() true, configurable state, POSIX
// resolveCwd. No SSH, no network — exercises the resolver's remote branch.
class FakeRemoteContext : public ExecutionContext
{
public:
explicit FakeRemoteContext(State s) : m_state(s) {}
bool isRemote() const override { return true; }
QString displayName() const override { return QStringLiteral("fake"); }
State state() const override { return m_state; }
IPtyProcess *createPty(QObject *) override { return nullptr; }
IGitProcessRunner *createGitRunner(QObject *) override { return nullptr; }
void exec(const QString &, const QStringList &, const QByteArray &, int,
ExecCallback) override {}
IFileSystemBackend *fsBackend() override { return nullptr; }
QString resolveCwd(const QString &requested) const override
{
QString p = requested.isEmpty() ? QStringLiteral("~") : requested;
p.replace(QLatin1Char('\\'), QLatin1Char('/'));
return QDir::cleanPath(p);
}
void setState(State s) { m_state = s; }
private:
State m_state;
};
class TestExecutionContextResolver : public QObject
{
Q_OBJECT
private slots:
void localContext_resolveCwd_cleansLocalPath();
void remoteContext_resolveCwd_posixNoLocalStat();
void resolver_nullContext_matchesLegacyLocal();
void resolver_localContext_matchesLegacyLocal();
void resolver_remoteConnected_returnsPosixPath();
void resolver_remoteDisconnected_returnsEmpty();
void resolver_remoteEmptyRequested_returnsEmpty();
void resolver_remotePathNotStattedLocally();
};
void TestExecutionContextResolver::localContext_resolveCwd_cleansLocalPath()
{
LocalExecutionContext local;
QCOMPARE(local.isRemote(), false);
QCOMPARE(local.state(), ExecutionContext::State::Connected);
QCOMPARE(local.resolveCwd(QStringLiteral("/a/b/../c")), QDir::cleanPath(QStringLiteral("/a/b/../c")));
QCOMPARE(local.resolveCwd(QString()), QString());
}
void TestExecutionContextResolver::remoteContext_resolveCwd_posixNoLocalStat()
{
FakeRemoteContext ctx(ExecutionContext::State::Connected);
// Backslashes normalized to POSIX; lexical clean only (no disk access).
QCOMPARE(ctx.resolveCwd(QStringLiteral("/srv/app/./logs")), QStringLiteral("/srv/app/logs"));
QCOMPARE(ctx.resolveCwd(QString()), QStringLiteral("~"));
}
void TestExecutionContextResolver::resolver_nullContext_matchesLegacyLocal()
{
// A null context must behave exactly like resolveWorkspace on a local path.
const QString existing = QDir::tempPath();
QCOMPARE(TerminalCwdResolver::resolveForContext(nullptr, existing),
TerminalCwdResolver::resolveWorkspace(existing));
}
void TestExecutionContextResolver::resolver_localContext_matchesLegacyLocal()
{
LocalExecutionContext local;
const QString existing = QDir::tempPath();
QCOMPARE(TerminalCwdResolver::resolveForContext(&local, existing),
TerminalCwdResolver::resolveWorkspace(existing));
// A non-existent local path still resolves empty (existing behavior).
const QString bogus = QDir::tempPath() + QStringLiteral("/nope/does/not/exist");
QCOMPARE(TerminalCwdResolver::resolveForContext(&local, bogus),
TerminalCwdResolver::resolveWorkspace(bogus));
}
void TestExecutionContextResolver::resolver_remoteConnected_returnsPosixPath()
{
FakeRemoteContext ctx(ExecutionContext::State::Connected);
QCOMPARE(TerminalCwdResolver::resolveForContext(&ctx, QStringLiteral("/home/alice/x/../proj")),
QStringLiteral("/home/alice/proj"));
}
void TestExecutionContextResolver::resolver_remoteDisconnected_returnsEmpty()
{
FakeRemoteContext ctx(ExecutionContext::State::Disconnected);
QCOMPARE(TerminalCwdResolver::resolveForContext(&ctx, QStringLiteral("/home/alice")), QString());
}
void TestExecutionContextResolver::resolver_remoteEmptyRequested_returnsEmpty()
{
FakeRemoteContext ctx(ExecutionContext::State::Connected);
QCOMPARE(TerminalCwdResolver::resolveForContext(&ctx, QString()), QString());
}
void TestExecutionContextResolver::resolver_remotePathNotStattedLocally()
{
// A remote path that surely does not exist on the local disk must still be
// returned verbatim (POSIX-normalized) — proving no local QFileInfo check.
FakeRemoteContext ctx(ExecutionContext::State::Connected);
const QString remotePath = QStringLiteral("/nonexistent-on-this-host/deep/remote/dir");
QCOMPARE(TerminalCwdResolver::resolveForContext(&ctx, remotePath), remotePath);
}
QTEST_APPLESS_MAIN(TestExecutionContextResolver)
#include "test_execution_context_resolver.moc"