Skip to content

Commit 2b1ef0b

Browse files
committed
Test mock spiffs
1 parent 2a62d55 commit 2b1ef0b

6 files changed

Lines changed: 304 additions & 14 deletions

File tree

data/json.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

data/map.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"map": {
3+
"color": "jaune",
4+
"vertices": [
5+
{ "id": 0, "point": { "x": 0, "y": 0 } },
6+
{ "id": 1, "point": { "x": 250, "y": 250 } },
7+
{ "id": 2, "point": { "x": 500, "y": 250 } }
8+
],
9+
"segments": [
10+
{ "id": 0, "start": { "x": 0, "y": 1500 }, "end": { "x": 1500, "y": 1500 } },
11+
{ "id": 1, "start": { "x": 1500, "y": 1500 }, "end": { "x": 1500, "y": 0 } }
12+
],
13+
"circles": [
14+
{ "id": 0, "center": { "x": 750, "y": 750 }, "radius": 100 },
15+
{ "id": 1, "center": { "x": 1200, "y": 300 }, "radius": 150 }
16+
]
17+
}
18+
}

include/FileSystem_Helper.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
#ifndef FILE_SYSTEM_HELPER_H
22
#define FILE_SYSTEM_HELPER_H
33

4+
#if defined(SIMULATOR)
5+
#include "MockSPIFFS.h"
6+
#define SPIFFS MockSPIFFS
7+
#define File MockFile
8+
#else
49
#include "SPIFFS.h"
10+
#endif
511
#include "ESP32_Helper.h"
612

713
/* You only need to format SPIFFS the first time you run a

include/MockSPIFFS.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#ifndef MOCK_SPIFFS_H
2+
#define MOCK_SPIFFS_H
3+
4+
#include <Arduino.h>
5+
#include <vector>
6+
7+
// Simple mock of SPIFFS for simulation: stores files in a vector and
8+
// provides a File-like API used by FileSystem_Helper.
9+
10+
// Provide FILE_WRITE/FILE_APPEND if missing (used by existing code)
11+
#ifndef FILE_WRITE
12+
#define FILE_WRITE 1
13+
#endif
14+
#ifndef FILE_APPEND
15+
#define FILE_APPEND 2
16+
#endif
17+
18+
struct MockFileEntry {
19+
String path;
20+
String content;
21+
};
22+
23+
class MockSPIFFSClass; // forward
24+
25+
class MockFile {
26+
public:
27+
MockFile() : owner(nullptr), idx(-1), isDir(false), pos(0), writable(false), valid(false) {}
28+
MockFile(MockSPIFFSClass* owner, int index, bool writable=false, bool isDir=false);
29+
30+
size_t print(const String& s);
31+
size_t println(const String& s);
32+
String readString();
33+
String readStringUntil(char c);
34+
int available();
35+
size_t size() const;
36+
void close();
37+
bool isDirectory() const;
38+
MockFile openNextFile();
39+
const char* name() const;
40+
size_t read(uint8_t* buffer, size_t len);
41+
size_t write(const uint8_t* buffer, size_t len);
42+
operator bool() const { return valid; }
43+
44+
private:
45+
MockSPIFFSClass* owner;
46+
int idx; // index into owner's files vector; -2 for directory handle
47+
bool isDir;
48+
int pos; // read position or dir iterator
49+
bool writable;
50+
bool valid;
51+
};
52+
53+
class MockSPIFFSClass {
54+
public:
55+
MockSPIFFSClass() {}
56+
57+
bool begin(bool formatOnFail = true);
58+
bool format();
59+
60+
// open with mode 'r','w','a' or with flags FILE_WRITE/FILE_APPEND
61+
MockFile open(const String& path, const char* mode = "r");
62+
MockFile open(const String& path, int flags);
63+
64+
bool exists(const String& path) const;
65+
bool remove(const String& path);
66+
bool rename(const String& from, const String& to);
67+
68+
// helper for tests: preload a file
69+
void preload(const String& path, const String& content);
70+
71+
private:
72+
std::vector<MockFileEntry> files;
73+
int indexOf(const String& path) const;
74+
75+
friend class MockFile;
76+
};
77+
78+
// provide fs::FS alias used by existing code
79+
namespace fs { using FS = MockSPIFFSClass; }
80+
81+
// instance used when SIMULATOR is defined (FileSystem_Helper.h maps SPIFFS to MockSPIFFS)
82+
extern MockSPIFFSClass MockSPIFFS;
83+
84+
#endif

platformio.ini

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,10 @@ build_flags =
5454
-D WITH_WIFI
5555

5656
[env:Example7_SPIFFS]
57+
build_unflags =
58+
-std=gnu++11
5759
build_flags =
58-
-D NO_WIFI
60+
-std=c++17
61+
-std=gnu++17
62+
-D NO_WIFI
63+
-D SIMULATOR

src/MockSPIFFS.cpp

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#include "MockSPIFFS.h"
2+
3+
// global instance
4+
MockSPIFFSClass MockSPIFFS;
5+
6+
// ---------------- MockFile ----------------
7+
MockFile::MockFile(MockSPIFFSClass* owner_, int index, bool writable_, bool isDir_)
8+
: owner(owner_), idx(index), isDir(isDir_), pos(0), writable(writable_), valid(true)
9+
{
10+
if (!owner_) { valid = false; return; }
11+
if (!isDir_ && (idx < 0 || idx >= (int)owner_->files.size())) { valid = false; }
12+
}
13+
14+
size_t MockFile::print(const String& s) {
15+
if (!valid || !writable) return 0;
16+
owner->files[idx].content += s;
17+
return s.length();
18+
}
19+
20+
size_t MockFile::println(const String& s) {
21+
return print(s + "\n");
22+
}
23+
24+
String MockFile::readString() {
25+
if (!valid) return String();
26+
String &c = owner->files[idx].content;
27+
String out = c.substring(pos);
28+
pos = c.length();
29+
return out;
30+
}
31+
32+
String MockFile::readStringUntil(char c) {
33+
if (!valid) return String();
34+
String &ct = owner->files[idx].content;
35+
int idxFound = ct.indexOf(c, pos);
36+
if (idxFound < 0) {
37+
String res = ct.substring(pos);
38+
pos = ct.length();
39+
return res;
40+
}
41+
String res = ct.substring(pos, idxFound);
42+
pos = idxFound + 1;
43+
return res;
44+
}
45+
46+
int MockFile::available() {
47+
if (!valid) return 0;
48+
return (int)owner->files[idx].content.length() - pos;
49+
}
50+
51+
size_t MockFile::size() const {
52+
if (!valid) return 0;
53+
return owner->files[idx].content.length();
54+
}
55+
56+
void MockFile::close() {
57+
// no-op
58+
}
59+
60+
bool MockFile::isDirectory() const {
61+
return isDir;
62+
}
63+
64+
MockFile MockFile::openNextFile() {
65+
if (!isDir) return MockFile();
66+
int total = (int)owner->files.size();
67+
if (pos >= total) return MockFile();
68+
int fileIdx = pos++;
69+
return MockFile(owner, fileIdx, false, false);
70+
}
71+
72+
const char* MockFile::name() const {
73+
if (!valid) return "";
74+
return owner->files[idx].path.c_str();
75+
}
76+
77+
size_t MockFile::read(uint8_t* buffer, size_t len) {
78+
if (!valid) return 0;
79+
String &c = owner->files[idx].content;
80+
if (pos >= (int)c.length()) return 0;
81+
size_t toRead = len;
82+
if (pos + (int)toRead > (int)c.length()) toRead = c.length() - pos;
83+
for (size_t i = 0; i < toRead; ++i) buffer[i] = (uint8_t)c[pos + i];
84+
pos += toRead;
85+
return toRead;
86+
}
87+
88+
size_t MockFile::write(const uint8_t* buffer, size_t len) {
89+
if (!valid || !writable) return 0;
90+
String &c = owner->files[idx].content;
91+
for (size_t i = 0; i < len; ++i) c += (char)buffer[i];
92+
return len;
93+
}
94+
95+
// ---------------- MockSPIFFSClass ----------------
96+
int MockSPIFFSClass::indexOf(const String& path) const {
97+
for (size_t i = 0; i < files.size(); ++i) if (files[i].path == path) return (int)i;
98+
return -1;
99+
}
100+
101+
bool MockSPIFFSClass::begin(bool formatOnFail){return true;}
102+
bool MockSPIFFSClass::format(){return true;}
103+
104+
MockFile MockSPIFFSClass::open(const String& path, const char* mode) {
105+
char m = (mode && mode[0]) ? mode[0] : 'r';
106+
if (path == "/") {
107+
MockFile dir(this, -2, false, true);
108+
return dir;
109+
}
110+
int idx = indexOf(path);
111+
if (m == 'r') {
112+
if (idx < 0) return MockFile();
113+
return MockFile(this, idx, false, false);
114+
} else if (m == 'w') {
115+
if (idx < 0) { files.push_back({path, ""}); idx = (int)files.size() - 1; }
116+
else files[idx].content = "";
117+
return MockFile(this, idx, true, false);
118+
} else if (m == 'a') {
119+
if (idx < 0) { files.push_back({path, ""}); idx = (int)files.size() - 1; }
120+
return MockFile(this, idx, true, false);
121+
}
122+
return MockFile();
123+
}
124+
125+
MockFile MockSPIFFSClass::open(const String& path, int flags) {
126+
#if defined(FILE_APPEND) && defined(FILE_WRITE)
127+
if (flags == FILE_APPEND) return open(path, "a");
128+
if (flags == FILE_WRITE) return open(path, "w");
129+
#endif
130+
if (flags != 0) return open(path, "w");
131+
return open(path, "r");
132+
}
133+
134+
bool MockSPIFFSClass::exists(const String& path) const {
135+
return indexOf(path) >= 0;
136+
}
137+
138+
bool MockSPIFFSClass::remove(const String& path) {
139+
int idx = indexOf(path);
140+
if (idx < 0) return false;
141+
files.erase(files.begin() + idx);
142+
return true;
143+
}
144+
145+
bool MockSPIFFSClass::rename(const String& from, const String& to) {
146+
int idx = indexOf(from);
147+
if (idx < 0) return false;
148+
int idxTo = indexOf(to);
149+
if (idxTo >= 0) {
150+
files[idxTo].content = files[idx].content;
151+
files.erase(files.begin() + idx);
152+
} else {
153+
files[idx].path = to;
154+
}
155+
return true;
156+
}
157+
158+
void MockSPIFFSClass::preload(const String& path, const String& content) {
159+
int idx = indexOf(path);
160+
if (idx < 0) files.push_back({path, content});
161+
else files[idx].content = content;
162+
}
163+
164+
// preload only texte.txt
165+
static bool _mockspiffs_preload = []() {
166+
MockSPIFFS.preload("texte.txt", "Hello World\n");
167+
String map_json = R"(
168+
{
169+
"map": {
170+
"color": "jaune",
171+
"vertices": [
172+
{ "id": 0, "point": { "x": 0, "y": 0 } },
173+
{ "id": 1, "point": { "x": 250, "y": 250 } },
174+
{ "id": 2, "point": { "x": 500, "y": 250 } }
175+
],
176+
"segments": [
177+
{ "id": 0, "start": { "x": 0, "y": 1500 }, "end": { "x": 1500, "y": 1500 } },
178+
{ "id": 1, "start": { "x": 1500, "y": 1500 }, "end": { "x": 1500, "y": 0 } }
179+
],
180+
"circles": [
181+
{ "id": 0, "center": { "x": 750, "y": 750 }, "radius": 100 },
182+
{ "id": 1, "center": { "x": 1200, "y": 300 }, "radius": 150 }
183+
]
184+
}
185+
}
186+
)";
187+
MockSPIFFS.preload("map.json", map_json);
188+
189+
return true;
190+
}();

0 commit comments

Comments
 (0)