ai-pp3
Version:
CLI tool combining multimodal AI analysis with RawTherapee's engine to generate optimized PP3 profiles for RAW photography
193 lines (190 loc) • 6.93 kB
JavaScript
import { describe, expect, it } from "vitest";
// We need to import the function from agent.ts, but it's not exported
// For testing purposes, let's create a test version
// Helper functions to reduce cognitive complexity
function findSectionHeader(searchLines) {
const sectionHeaderLine = searchLines.find((line) => line.trim().startsWith("["));
return sectionHeaderLine ? sectionHeaderLine.trim() : null;
}
function findSectionEndIndex(contentLines, sectionStartIndex) {
let sectionEndIndex = contentLines.length;
for (let index = sectionStartIndex + 1; index < contentLines.length; index++) {
const line = contentLines[index].trim();
if (line.startsWith("[") && line.endsWith("]")) {
sectionEndIndex = index;
break;
}
}
return sectionEndIndex;
}
function extractParameters(lines) {
return lines
.filter((line) => !line.trim().startsWith("[") && line.trim().length > 0)
.map((line) => line.trim());
}
function createReplaceMap(searchParameters, replaceParameters) {
const replaceMap = new Map();
for (const [index, searchParameter] of searchParameters.entries()) {
const replaceParameter = replaceParameters[index];
const searchParameterName = searchParameter.split("=")[0];
replaceMap.set(searchParameterName, replaceParameter);
}
return replaceMap;
}
function applyFuzzySearchReplace(content, search, replace) {
// This is a simplified version for testing - we'll import the actual function later
const searchLines = search.trim().split("\n");
const replaceLines = replace.trim().split("\n");
const contentLines = content.split("\n");
// Find the section header
const sectionHeader = findSectionHeader(searchLines);
if (!sectionHeader) {
return content.replace(search.trim(), replace.trim());
}
const sectionStartIndex = contentLines.findIndex((line) => line.trim() === sectionHeader);
if (sectionStartIndex === -1) {
return content;
}
// Find section end
const sectionEndIndex = findSectionEndIndex(contentLines, sectionStartIndex);
// Extract parameters
const searchParameters = extractParameters(searchLines);
const replaceParameters = extractParameters(replaceLines);
if (searchParameters.length !== replaceParameters.length) {
return content.replace(search.trim(), replace.trim());
}
// Create replacement map
const replaceMap = createReplaceMap(searchParameters, replaceParameters);
// Apply replacements
const result = [...contentLines];
const indentationRegex = /^\s*/;
for (let index = sectionStartIndex + 1; index < sectionEndIndex; index++) {
const line = result[index].trim();
if (line.length === 0)
continue;
const parameterName = line.split("=")[0];
if (replaceMap.has(parameterName)) {
const originalIndentation = indentationRegex.exec(result[index])?.[0] ?? "";
const replacementValue = replaceMap.get(parameterName);
if (replacementValue !== undefined) {
result[index] = originalIndentation + replacementValue;
}
}
}
return result.join("\n");
}
describe("Fuzzy Search/Replace", () => {
const samplePP3Content = `[Version]
AppVersion=5.11
Version=351
[General]
ColorLabel=0
InTrash=false
[ColorToning]
Enabled=false
Method=LabRegions
Lumamode=true
Twocolor=Std
Redlow=0
Greenlow=0
Bluelow=0
Satlow=0
Balance=0
[Exposure]
Auto=false
Clip=0.02
Compensation=0
Brightness=0
Contrast=0`;
it("should handle line skipping in ColorToning section", () => {
const search = `[ColorToning]
Lumamode=true
Twocolor=Std
Redlow=0`;
const replace = `[ColorToning]
Lumamode=true
Twocolor=Std
Redlow=20`;
const result = applyFuzzySearchReplace(samplePP3Content, search, replace);
expect(result).toContain("Redlow=20");
expect(result).toContain("Enabled=false");
expect(result).toContain("Method=LabRegions");
expect(result).toContain("Lumamode=true");
expect(result).toContain("Twocolor=Std");
});
it("should preserve indentation", () => {
const contentWithIndentation = `[ColorToning]
Enabled=false
Method=LabRegions
Lumamode=true
Twocolor=Std
Redlow=0`;
const search = `[ColorToning]
Lumamode=true
Redlow=0`;
const replace = `[ColorToning]
Lumamode=false
Redlow=25`;
const result = applyFuzzySearchReplace(contentWithIndentation, search, replace);
expect(result).toContain(" Lumamode=false");
expect(result).toContain(" Redlow=25");
expect(result).toContain(" Enabled=false");
});
it("should handle multiple parameter changes", () => {
const search = `[ColorToning]
Lumamode=true
Redlow=0
Greenlow=0
Balance=0`;
const replace = `[ColorToning]
Lumamode=false
Redlow=15
Greenlow=10
Balance=5`;
const result = applyFuzzySearchReplace(samplePP3Content, search, replace);
expect(result).toContain("Lumamode=false");
expect(result).toContain("Redlow=15");
expect(result).toContain("Greenlow=10");
expect(result).toContain("Balance=5");
// Should preserve other parameters
expect(result).toContain("Enabled=false");
expect(result).toContain("Method=LabRegions");
});
it("should fallback to exact match when no section header found", () => {
const search = "Auto=false";
const replace = "Auto=true";
const result = applyFuzzySearchReplace(samplePP3Content, search, replace);
expect(result).toContain("Auto=true");
});
it("should return original content when section not found", () => {
const search = `[NonExistentSection]
Param=value`;
const replace = `[NonExistentSection]
Param=newvalue`;
const result = applyFuzzySearchReplace(samplePP3Content, search, replace);
expect(result).toBe(samplePP3Content);
});
it("should handle parameter count mismatch", () => {
const search = `[ColorToning]
Lumamode=true
Redlow=0`;
const replace = `[ColorToning]
Lumamode=false`;
const result = applyFuzzySearchReplace(samplePP3Content, search, replace);
// Should fallback to exact match, which won't find anything
expect(result).toBe(samplePP3Content);
});
it("should not affect other sections", () => {
const search = `[ColorToning]
Redlow=0`;
const replace = `[ColorToning]
Redlow=50`;
const result = applyFuzzySearchReplace(samplePP3Content, search, replace);
expect(result).toContain("Redlow=50");
// Exposure section should remain unchanged
expect(result).toContain("[Exposure]");
expect(result).toContain("Auto=false");
expect(result).toContain("Clip=0.02");
});
});
//# sourceMappingURL=fuzzy-search-replace.test.js.map