diff --git a/tools/cdata-test.js b/tools/cdata-test.js index 82ed3ed51..e350ee680 100644 --- a/tools/cdata-test.js +++ b/tools/cdata-test.js @@ -1,6 +1,7 @@ 'use strict'; + const assert = require('node:assert'); -const { describe, it, before, after, afterEach, mock, test, run } = require('node:test'); +const { describe, it, before, after } = require('node:test'); const fs = require('fs'); const path = require('path'); const child_process = require('child_process'); @@ -10,15 +11,13 @@ const execPromise = util.promisify(child_process.exec); process.env.NODE_ENV = 'test'; // Set the environment to testing const cdata = require('./cdata.js'); -describe('Functions', () => { +describe('Function', () => { const testFolderPath = path.join(__dirname, 'testFolder'); const oldFilePath = path.join(testFolderPath, 'oldFile.txt'); const newFilePath = path.join(testFolderPath, 'newFile.txt'); // Create a temporary file before the test before(() => { - fs.writeFileSync('temp.txt', 'Hello World'); - // Create test folder if (!fs.existsSync(testFolderPath)) { fs.mkdirSync(testFolderPath); @@ -35,53 +34,53 @@ describe('Functions', () => { fs.writeFileSync(newFilePath, 'This is a new file.'); }); - // delete the temporary file after the test + // delete the temporary files after the test after(() => { - fs.unlinkSync('temp.txt'); - - // Delete test folder - if (fs.existsSync(testFolderPath)) { - fs.rmSync(testFolderPath, { recursive: true }); - } + fs.rmSync(testFolderPath, { recursive: true }); }); describe('isFileNewerThan', async () => { it('should return true if the file is newer than the provided time', async () => { const pastTime = Date.now() - 10000; // 10 seconds ago - assert.strictEqual(cdata.isFileNewerThan('temp.txt', pastTime), true); + assert.strictEqual(cdata.isFileNewerThan(newFilePath, pastTime), true); }); it('should return false if the file is older than the provided time', async () => { - const futureTime = Date.now() + 10000; // 10 seconds in the future - assert.strictEqual(cdata.isFileNewerThan('temp.txt', futureTime), false); + assert.strictEqual(cdata.isFileNewerThan(oldFilePath, Date.now()), false); }); - it('should return false if the file does not exist', async () => { - assert.strictEqual(cdata.isFileNewerThan('nonexistent.txt', Date.now()), false); + it('should throw an exception if the file does not exist', async () => { + assert.throws(() => { + cdata.isFileNewerThan('nonexistent.txt', Date.now()); + }); }); }); describe('isAnyFileInFolderNewerThan', async () => { it('should return true if a file in the folder is newer than the given time', async () => { - const folderPath = path.join(__dirname, 'testFolder'); - const time = fs.statSync(path.join(folderPath, 'oldFile.txt')).mtime; - assert.strictEqual(cdata.isAnyFileInFolderNewerThan(folderPath, time), true); + const time = fs.statSync(path.join(testFolderPath, 'oldFile.txt')).mtime; + assert.strictEqual(cdata.isAnyFileInFolderNewerThan(testFolderPath, time), true); }); it('should return false if no files in the folder are newer than the given time', async () => { - const folderPath = path.join(__dirname, 'testFolder'); - const time = new Date(); - assert.strictEqual(cdata.isAnyFileInFolderNewerThan(folderPath, time), false); + assert.strictEqual(cdata.isAnyFileInFolderNewerThan(testFolderPath, new Date()), false); + }); + + it('should throw an exception if the folder does not exist', async () => { + assert.throws(() => { + cdata.isAnyFileInFolderNewerThan('nonexistent', new Date()); + }); }); }); }); -describe('General functionality', () => { +describe('Script', () => { const folderPath = 'wled00'; const dataPath = path.join(folderPath, 'data'); before(() => { process.env.NODE_ENV = 'production'; + // Backup files fs.cpSync("wled00/data", "wled00Backup", { recursive: true }); fs.cpSync("tools/cdata.js", "cdata.bak.js"); }); @@ -93,26 +92,54 @@ describe('General functionality', () => { fs.renameSync("cdata.bak.js", "tools/cdata.js"); }); - describe('Script', () => { - it('should create html_*.h files if they are missing', async () => { - // delete all html_*.h files - let files = await fs.promises.readdir(folderPath); - await Promise.all(files.map(file => { - if (file.startsWith('html_') && path.extname(file) === '.h') { - return fs.promises.unlink(path.join(folderPath, file)); - } - })); + // delete all html_*.h files + async function deleteBuiltFiles() { + const files = await fs.promises.readdir(folderPath); + await Promise.all(files.map(file => { + if (file.startsWith('html_') && path.extname(file) === '.h') { + return fs.promises.unlink(path.join(folderPath, file)); + } + })); + } - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); + // check if html_*.h files were created + async function checkIfBuiltFilesExist() { + const files = await fs.promises.readdir(folderPath); + const htmlFiles = files.filter(file => file.startsWith('html_') && path.extname(file) === '.h'); + assert(htmlFiles.length > 0, 'html_*.h files were not created'); + } - // check if html_*.h files were created - files = await fs.promises.readdir(folderPath); - const htmlFiles = files.filter(file => file.startsWith('html_') && path.extname(file) === '.h'); - assert(htmlFiles.length > 0, 'html_*.h files were not created'); + async function runAndCheckIfBuiltFilesExist() { + await execPromise('node tools/cdata.js'); + await checkIfBuiltFilesExist(); + } + + async function testFileModification(sourceFilePath, resultFile) { + // run cdata.js to ensure html_*.h files are created + await execPromise('node tools/cdata.js'); + + // modify file + fs.appendFileSync(sourceFilePath, ' '); + // delay for 1 second to ensure the modified time is different + await new Promise(resolve => setTimeout(resolve, 1000)); + + // run script cdata.js again and wait for it to finish + await execPromise('node tools/cdata.js'); + + // check if web ui was rebuilt + const stats = fs.statSync(path.join(folderPath, resultFile)); + const modifiedTime = stats.mtimeMs; + const currentTime = Date.now(); + assert(currentTime - modifiedTime < 500, resultFile + ' was not modified'); + } + + describe('should build if', () => { + it('html_*.h files are missing', async () => { + await deleteBuiltFiles(); + await runAndCheckIfBuiltFilesExist(); }); - it('should rebuild if 1 or more html_*.h files are missing', async () => { + it('1 or more html_*.h files are missing', async () => { // run script cdata.js and wait for it to finish await execPromise('node tools/cdata.js'); @@ -124,23 +151,33 @@ describe('General functionality', () => { await fs.promises.unlink(path.join(folderPath, randomFile)); } - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); - - // check if html_*.h files were created - files = await fs.promises.readdir(folderPath); - htmlFiles = files.filter(file => file.startsWith('html_') && path.extname(file) === '.h'); - assert(htmlFiles.length > 0, 'html_*.h files were not created'); + await runAndCheckIfBuiltFilesExist(); }); - it('should not rebuild if the files are already built', async () => { - // delete all html_*.h files - let files = await fs.promises.readdir(folderPath); - await Promise.all(files.map(file => { - if (file.startsWith('html_') && path.extname(file) === '.h') { - return fs.promises.unlink(path.join(folderPath, file)); - } - })); + it('a file changes', async () => { + await testFileModification(path.join(dataPath, 'index.htm'), 'html_ui.h'); + }); + + it('a inlined file changes', async () => { + await testFileModification(path.join(dataPath, 'index.js'), 'html_ui.h'); + }); + + it('a settings file changes', async () => { + await testFileModification(path.join(dataPath, 'settings_leds.htm'), 'html_ui.h'); + }); + + it('the favicon changes', async () => { + await testFileModification(path.join(dataPath, 'favicon.ico'), 'html_ui.h'); + }); + + it('cdata.js changes', async () => { + await testFileModification('tools/cdata.js', 'html_ui.h'); + }); + }); + + describe('should not build if', () => { + it('the files are already built', async () => { + await deleteBuiltFiles(); // run script cdata.js and wait for it to finish let startTime = Date.now(); @@ -155,62 +192,5 @@ describe('General functionality', () => { // check if second run was faster than the first (must be at least 2x faster) assert(secondRunTime < firstRunTime / 2, 'html_*.h files were rebuilt'); }); - - it('should rebuild if a file changes', async () => { - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); - - // modify index.htm - fs.appendFileSync(path.join(dataPath, 'index.htm'), ' '); - // delay for 1 second to ensure the modified time is different - await new Promise(resolve => setTimeout(resolve, 1000)); - - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); - - // check if html_ui.h was modified - const stats = fs.statSync(path.join(folderPath, 'html_ui.h')); - const modifiedTime = stats.mtimeMs; - const currentTime = Date.now(); - assert(currentTime - modifiedTime < 500, 'html_ui.h was not modified'); - }); - - it('should rebuild if a inlined file changes', async () => { - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); - - // modify index.htm - fs.appendFileSync(path.join(dataPath, 'index.js'), ' '); - // delay for 1 second to ensure the modified time is different - await new Promise(resolve => setTimeout(resolve, 1000)); - - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); - - // check if html_ui.h was modified - const stats = fs.statSync(path.join(folderPath, 'html_ui.h')); - const modifiedTime = stats.mtimeMs; - const currentTime = Date.now(); - assert(currentTime - modifiedTime < 500, 'html_ui.h was not modified'); - }); - - it('should rebuild if a cdata.js has been modified', async () => { - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); - - // modify index.htm - fs.appendFileSync('tools/cdata.js', ' '); - // delay for 1 second to ensure the modified time is different - await new Promise(resolve => setTimeout(resolve, 1000)); - - // run script cdata.js and wait for it to finish - await execPromise('node tools/cdata.js'); - - // check if html_ui.h was modified - const stats = fs.statSync(path.join(folderPath, 'html_ui.h')); - const modifiedTime = stats.mtimeMs; - const currentTime = Date.now(); - assert(currentTime - modifiedTime < 500, 'html_ui.h was not modified'); - }); }); }); \ No newline at end of file diff --git a/tools/cdata.js b/tools/cdata.js index 2d257866c..acffd0140 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -188,13 +188,8 @@ async function writeChunks(srcDir, specs, resultFile) { // Check if a file is newer than a given time function isFileNewerThan(filePath, time) { - try { - const stats = fs.statSync(filePath); - return stats.mtimeMs > time; - } catch (e) { - console.error(`Failed to get stats for file ${filePath}:`, e); - return false; - } + const stats = fs.statSync(filePath); + return stats.mtimeMs > time; } // Check if any file in a folder (or its subfolders) is newer than a given time @@ -219,8 +214,9 @@ function isAlreadyBuilt(folderPath) { for (const file of output) { try { lastBuildTime = Math.min(lastBuildTime, fs.statSync(file).mtimeMs); - } - catch (e) { + } catch (e) { + if (e.code !== 'ENOENT') throw e; + console.info("File " + file + " does not exist. Rebuilding..."); return false; } }