Improved grammar to allow multiple expressions in a function parameter

This commit is contained in:
0xb00bface 2023-03-11 13:59:27 +01:00
parent 699a99608e
commit 69ea8e0b92
17 changed files with 262 additions and 138 deletions

View File

@ -170,7 +170,7 @@ public class Player {
StreamSource best;
int maxRes = Config.getInstance().getSettings().maximumResolutionPlayer;
if (maxRes > 0 && !sources.isEmpty()) {
for (Iterator<StreamSource> iterator = sources.iterator(); iterator.hasNext();) {
for (Iterator<StreamSource> iterator = sources.iterator(); iterator.hasNext(); ) {
StreamSource streamSource = iterator.next();
if (streamSource.height > 0 && maxRes < streamSource.height) {
LOG.trace("Res too high {} > {}", streamSource.height, maxRes);
@ -188,7 +188,7 @@ public class Player {
}
private void expandPlaceHolders(String[] cmdline) {
ModelVariableExpander expander = new ModelVariableExpander(model, Config.getInstance(), null);
ModelVariableExpander expander = new ModelVariableExpander(model, Config.getInstance(), null, null);
for (int i = 0; i < cmdline.length; i++) {
var param = cmdline[i];
param = expander.expand(param);

View File

@ -1,43 +1,49 @@
package ctbrec.ui.action;
import java.io.File;
import java.time.Instant;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.Settings.DirectoryStructure;
import ctbrec.ui.DesktopIntegration;
import ctbrec.ui.controls.Dialogs;
import javafx.scene.Cursor;
import javafx.scene.Node;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.time.Instant;
@Slf4j
@RequiredArgsConstructor
public class OpenRecordingsDir {
private Model selectedModel;
private Node source;
public OpenRecordingsDir(Node source, Model selectedModel) {
this.source = source;
this.selectedModel = selectedModel;
}
private final Node source;
private final Model selectedModel;
public void execute() {
source.setCursor(Cursor.WAIT);
var fileForRecording = Config.getInstance().getFileForRecording(selectedModel, ".mp4", Instant.now());
final File dir = getModelDirectory(fileForRecording);
var dir = Config.getInstance().getFileForRecording(selectedModel, ".mp4", Instant.now());
dir = findDeepestExistingDir(dir);
log.info("Directory for model is {}", dir.getAbsolutePath());
if (dir.exists()) {
GlobalThreadPool.submit(() -> DesktopIntegration.open(dir));
final File directory = dir;
GlobalThreadPool.submit(() -> DesktopIntegration.open(directory));
} else {
Dialogs.showError(source.getScene(), "Directory does not exist", "There are no recordings for this model", null);
}
source.setCursor(Cursor.DEFAULT);
}
private File getModelDirectory(File fileForRecording) {
var dir = fileForRecording.getParentFile();
if (Config.getInstance().getSettings().recordingsDirStructure == DirectoryStructure.ONE_PER_RECORDING) {
dir = dir.getParentFile();
private File findDeepestExistingDir(File dir) {
while (!dir.exists()) {
if (dir.getParentFile() == null) {
return dir;
} else {
dir = dir.getParentFile();
if (dir.exists()) {
break;
}
}
}
return dir;
}

View File

@ -123,6 +123,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
private LocalTimeProperty timeoutRecordingEndingAt;
private SimpleLongProperty recordUntilDefaultDurationInMinutes;
private SimpleStringProperty dateTimeFormat;
private final VariablePlayGroundDialogFactory variablePlayGroundDialogFactory = new VariablePlayGroundDialogFactory();
public SettingsTab(List<Site> sites, Recorder recorder) {
this.sites = sites;
@ -379,9 +380,9 @@ public class SettingsTab extends Tab implements TabSelectionListener {
}
private Button createVariablePlayGroundButton() {
var postProcessingHelpButton = new Button("Variable Playground");
postProcessingHelpButton.setOnAction(e -> new VariablePlayGroundDialogFactory().openDialog(this.getTabPane().getScene(), config, recorder));
return postProcessingHelpButton;
var button = new Button("Variable Playground");
button.setOnAction(e -> variablePlayGroundDialogFactory.openDialog(this.getTabPane().getScene(), config, recorder));
return button;
}
private void bindEnabledProperty(Setting s, BooleanExpression bindTo) {

View File

@ -5,42 +5,53 @@ import ctbrec.Recording;
import ctbrec.StringUtil;
import ctbrec.UnknownModel;
import ctbrec.recorder.Recorder;
import ctbrec.recorder.postprocessing.PostProcessingContext;
import ctbrec.sites.chaturbate.Chaturbate;
import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.tabs.DownloadPostprocessor;
import ctbrec.variableexpansion.ConfigVariableExpander;
import ctbrec.variableexpansion.ModelVariableExpander;
import ctbrec.variableexpansion.RecordingVariableExpander;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import java.nio.file.Paths;
import java.time.Instant;
@Slf4j
public class VariablePlayGroundDialogFactory {
private GridPane pane;
public void openDialog(Scene parent, Config config, Recorder recorder) {
if (pane == null) {
initGui(config, recorder);
}
Dialogs.showCustomInput(parent, "Playground", pane, (obs, oldV, newV) -> {
});
}
private void initGui(Config config, Recorder recorder) {
Chaturbate chaturbate = new Chaturbate();
UnknownModel unknownModel = new UnknownModel();
unknownModel.setName("Pussy_Galore");
unknownModel.setDisplayName("Pussy Galore");
unknownModel.setSite(chaturbate);
unknownModel.setUrl("http://camsite.example/pussy_galore");
Recording recording = new Recording();
recording.setAbsoluteFile(Paths.get("ctbrec", "recs", "pussy_galore", "2023-02-26_14-05-56").toFile());
recording.setStartDate(Instant.now());
recording.setStatus(Recording.State.POST_PROCESSING);
recording.setNote("notes about the recording");
recording.setModel(unknownModel);
PostProcessingContext ctx = new PostProcessingContext();
ctx.setConfig(config);
ctx.setRecorder(recorder);
ctx.setRecording(recording);
DownloadPostprocessor postprocessor = new DownloadPostprocessor();
GridPane pane = new GridPane();
pane = new GridPane();
Label result = new Label();
Label error = new Label();
@ -49,18 +60,6 @@ public class VariablePlayGroundDialogFactory {
input.setMinWidth(600);
pane.add(input, 1, 0);
GridPane.setHgrow(input, Priority.ALWAYS);
input.setOnKeyTyped(evt -> {
String r = postprocessor.fillInPlaceHolders(input.getText(), ctx, new AntlrSyntacErrorAdapter() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object o, int line, int pos, String s, RecognitionException e) {
error.setText(String.format("Syntax error at %d:%d %s", line, pos, s));
}
});
result.setText(r);
if (StringUtil.isNotBlank(r)) {
error.setText("");
}
});
pane.add(error, 0, 1);
GridPane.setColumnSpan(error, 2);
@ -70,7 +69,31 @@ public class VariablePlayGroundDialogFactory {
pane.setHgap(5);
pane.vgapProperty().bind(pane.hgapProperty());
Dialogs.showCustomInput(parent, "Playground", pane, (obs, oldV, newV) -> {
AntlrSyntacErrorAdapter errorHandler = new AntlrSyntacErrorAdapter() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object o, int line, int pos, String s, RecognitionException e) {
error.setText(String.format("Syntax error at %d:%d %s", line, pos, s));
}
};
ModelVariableExpander modelVariableExpander = new ModelVariableExpander(unknownModel, config, recorder, errorHandler);
RecordingVariableExpander recordingVariableExpander = new RecordingVariableExpander(recording, errorHandler);
ConfigVariableExpander configVariableExpander = new ConfigVariableExpander(config, errorHandler);
input.setOnKeyTyped(evt -> {
try {
String r = input.getText();
modelVariableExpander.getPlaceholderValueSuppliers().putAll(recordingVariableExpander.getPlaceholderValueSuppliers());
modelVariableExpander.getPlaceholderValueSuppliers().putAll(configVariableExpander.getPlaceholderValueSuppliers());
r = modelVariableExpander.expand(r);
result.setText(r);
if (StringUtil.isNotBlank(r)) {
error.setText("");
}
} catch (Exception e) {
log.error("Error", e);
}
});
}
}

View File

@ -2,11 +2,13 @@ grammar PostProcessing;
line: (text | variable | functionCall)* EOF;
functionCall: '$' identifier '(' (expression (',' expression)*)? ')';
functionCall: '$' identifier '(' (parameter (',' parameter)*)? ')';
text: CH+?;
identifier: CH+?;
parameter: expression*;
variable: '${' identifier '}';
expression

View File

@ -183,9 +183,8 @@ public class Config {
}
private void migrateOldSettings() {
// 4.7.18
// 5.0.0
convertChaturbateModelNamesToLowerCase();
}
private void convertChaturbateModelNamesToLowerCase() {

View File

@ -2,29 +2,11 @@ package ctbrec.recorder.postprocessing;
import ctbrec.Config;
import ctbrec.Recording;
import ctbrec.StringUtil;
import ctbrec.variableexpansion.ConfigVariableExpander;
import ctbrec.variableexpansion.ModelVariableExpander;
import ctbrec.variableexpansion.ParserVisitor;
import ctbrec.variableexpansion.VariableExpansionException;
import ctbrec.variableexpansion.antlr.PostProcessingLexer;
import ctbrec.variableexpansion.antlr.PostProcessingParser;
import ctbrec.variableexpansion.RecordingVariableExpander;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.IOException;
import java.io.StringReader;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static java.util.Optional.ofNullable;
@Slf4j
public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPostProcessor {
@ -37,58 +19,11 @@ public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPost
Recording rec = ctx.getRecording();
Config config = ctx.getConfig();
ModelVariableExpander modelExpander = new ModelVariableExpander(rec.getModel(), config, ctx.getRecorder());
Map<String, Optional<Object>> variables = new HashMap<>(modelExpander.getPlaceholderValueSuppliers());
variables.put("recordingNotes", getSanitizedRecordingNotes(rec));
variables.put("fileSuffix", getFileSuffix(rec));
variables.put("recordingsDir", Optional.of(config.getSettings().recordingsDir));
variables.put("absolutePath", Optional.of(rec.getPostProcessedFile().getAbsolutePath()));
variables.put("absoluteParentPath", Optional.of(rec.getPostProcessedFile().getParentFile().getAbsolutePath()));
variables.put("epochSecond", ofNullable(rec.getStartDate()).map(Instant::getEpochSecond).map(l -> Long.toString(l))); // NOSONAR
variables.put("utcDateTime", getUtcDateTime(rec));
variables.put("localDateTime", getLocalDateTime(rec));
return fillInPlaceHolders(input, variables, errorListener);
}
private String fillInPlaceHolders(String input, Map<String, Optional<Object>> variables, AntlrSyntacErrorAdapter errorListener) {
try (StringReader reader = new StringReader(input)) {
CharStream s = CharStreams.fromReader(reader);
PostProcessingLexer lexer = new PostProcessingLexer(s);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PostProcessingParser parser = new PostProcessingParser(tokens);
Optional.ofNullable(errorListener).ifPresent(parser::addErrorListener);
ParseTree parseTree = parser.line();
ParserVisitor visitor = new ParserVisitor(variables);
return visitor.visit(parseTree);
} catch (IOException e) {
throw new VariableExpansionException("Couldn't replace placeholders", e);
}
}
protected Optional<Object> getUtcDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneOffset.UTC));
}
protected Optional<Object> getLocalDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneId.systemDefault()));
}
private Optional<Object> getFileSuffix(Recording rec) {
if (rec.isSingleFile()) {
String filename = rec.getPostProcessedFile().getName();
return Optional.of(filename.substring(filename.lastIndexOf('.') + 1));
} else {
return Optional.empty();
}
}
private Optional<Object> getSanitizedRecordingNotes(Recording rec) {
Optional<String> notes = ofNullable(rec.getNote());
return notes.map(StringUtil::sanitize);
ModelVariableExpander modelExpander = new ModelVariableExpander(rec.getModel(), config, ctx.getRecorder(), errorListener);
RecordingVariableExpander recordingExpander = new RecordingVariableExpander(rec, errorListener);
ConfigVariableExpander configExpander = new ConfigVariableExpander(config, errorListener);
modelExpander.getPlaceholderValueSuppliers().putAll(recordingExpander.getPlaceholderValueSuppliers());
modelExpander.getPlaceholderValueSuppliers().putAll(configExpander.getPlaceholderValueSuppliers());
return modelExpander.expand(input);
}
}

View File

@ -4,8 +4,11 @@ import ctbrec.variableexpansion.antlr.PostProcessingLexer;
import ctbrec.variableexpansion.antlr.PostProcessingParser;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
@ -17,18 +20,19 @@ abstract class AbstractVariableExpander {
protected Map<String, Optional<Object>> placeholderValueSuppliers = new HashMap<>();
protected AntlrSyntacErrorAdapter errorListener;
AbstractVariableExpander(@Nullable AntlrSyntacErrorAdapter errorListener) {
this.errorListener = errorListener;
}
protected String fillInPlaceHolders(String input, Map<String, Optional<Object>> variables) {
try (StringReader reader = new StringReader(input)) {
CharStream s = CharStreams.fromReader(reader);
PostProcessingLexer lexer = new PostProcessingLexer(s);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PostProcessingParser parser = new PostProcessingParser(tokens);
parser.addErrorListener(new AntlrSyntacErrorAdapter() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object o, int line, int pos, String s, RecognitionException e) {
log.warn("Syntax error at {}:{} {}", line, pos, s);
}
});
Optional.ofNullable(errorListener).ifPresent(parser::addErrorListener);
PostProcessingParser.LineContext ctx = parser.line();
ParserVisitor visitor = new ParserVisitor(variables);
return visitor.visit(ctx);

View File

@ -0,0 +1,18 @@
package ctbrec.variableexpansion;
import ctbrec.Config;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import java.util.Optional;
public class ConfigVariableExpander extends AbstractVariableExpander {
public ConfigVariableExpander(Config config, AntlrSyntacErrorAdapter errorListener) {
super(errorListener);
placeholderValueSuppliers.put("recordingsDir", Optional.of(config.getSettings().recordingsDir));
}
public String expand(String input) {
return fillInPlaceHolders(input, placeholderValueSuppliers);
}
}

View File

@ -6,6 +6,7 @@ import ctbrec.ModelGroup;
import ctbrec.StringUtil;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import java.util.Optional;
import java.util.UUID;
@ -14,7 +15,8 @@ import static java.util.Optional.ofNullable;
public class ModelVariableExpander extends AbstractVariableExpander {
public ModelVariableExpander(Model model, Config config, Recorder recorder) {
public ModelVariableExpander(Model model, Config config, Recorder recorder, AntlrSyntacErrorAdapter errorListener) {
super(errorListener);
Optional<ModelGroup> modelGroup = Optional.ofNullable(recorder).flatMap(r -> r.getModelGroup(model));
placeholderValueSuppliers.put("modelName", ofNullable(model.getName()));
placeholderValueSuppliers.put("modelDisplayName", ofNullable(model.getDisplayName()));

View File

@ -30,8 +30,8 @@ public class ParserVisitor extends PostProcessingBaseVisitor<String> {
String identifier = ctx.identifier().getText();
VarArgsFunction<Object, String> function = functions.get(identifier);
if (function != null) {
List<PostProcessingParser.ExpressionContext> parameters = ctx.expression();
List<String> params = parameters.stream().map(this::visitExpression).toList();
List<PostProcessingParser.ParameterContext> parameters = ctx.parameter();
List<String> params = parameters.stream().map(this::visitParameter).toList();
return function.apply(params.toArray(new Object[0]));
} else {
return ctx.getText();
@ -45,7 +45,7 @@ public class ParserVisitor extends PostProcessingBaseVisitor<String> {
if (value != null && value.isPresent()) { // NOSONAR
return value.get().toString();
} else {
return "";
return ctx.getText();
}
}

View File

@ -0,0 +1,58 @@
package ctbrec.variableexpansion;
import ctbrec.Recording;
import ctbrec.StringUtil;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import java.io.File;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Optional;
import static java.util.Optional.ofNullable;
public class RecordingVariableExpander extends AbstractVariableExpander {
public RecordingVariableExpander(Recording rec, AntlrSyntacErrorAdapter errorListener) {
super(errorListener);
placeholderValueSuppliers.put("recordingNotes", getSanitizedRecordingNotes(rec));
placeholderValueSuppliers.put("fileSuffix", getFileSuffix(rec));
placeholderValueSuppliers.put("absolutePath", Optional.of(rec).map(Recording::getPostProcessedFile).map(File::getAbsolutePath));
placeholderValueSuppliers.put("absoluteParentPath", Optional.of(rec).map(Recording::getPostProcessedFile).map(File::getParentFile).map(File::getAbsolutePath));
placeholderValueSuppliers.put("epochSecond", ofNullable(rec.getStartDate()).map(Instant::getEpochSecond).map(l -> Long.toString(l))); // NOSONAR
placeholderValueSuppliers.put("utcDateTime", getUtcDateTime(rec));
placeholderValueSuppliers.put("localDateTime", getLocalDateTime(rec));
}
public String expand(String input) {
return fillInPlaceHolders(input, placeholderValueSuppliers);
}
protected Optional<Object> getUtcDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneOffset.UTC));
}
protected Optional<Object> getLocalDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneId.systemDefault()));
}
private Optional<Object> getFileSuffix(Recording rec) {
if (rec.isSingleFile()) {
String filename = rec.getPostProcessedFile().getName();
return Optional.of(filename.substring(filename.lastIndexOf('.') + 1));
} else {
return Optional.empty();
}
}
private Optional<Object> getSanitizedRecordingNotes(Recording rec) {
Optional<String> notes = ofNullable(rec.getNote());
return notes.map(StringUtil::sanitize);
}
}

View File

@ -4,8 +4,13 @@ import ctbrec.StringUtil;
import ctbrec.variableexpansion.VarArgsFunction;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OrElse implements VarArgsFunction<Object, String> {
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{[^${}]+}");
@Override
public String apply(Object... params) {
if (params == null || params.length < 1) {
@ -18,7 +23,13 @@ public class OrElse implements VarArgsFunction<Object, String> {
Optional<String> result = Optional.ofNullable(params[0]).map(String::valueOf);
if (result.isPresent() && StringUtil.isNotBlank(result.get())) {
return result.get();
String param = result.get();
Matcher m = VARIABLE_PATTERN.matcher(param);
if (m.find()) {
return fallback;
} else {
return result.get();
}
} else {
return fallback;
}

View File

@ -49,9 +49,9 @@ class AbstractPlaceholderAwarePostProcessorTest extends AbstractPpTest {
@Test
void testSiteNameReplacement() {
String input = "asdf_${siteName}_asdf";
assertEquals("asdf_Chaturbate_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
assertEquals("asdf_Stripchat_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
input = "asdf_$sanitize(${siteName})_asdf";
assertEquals("asdf_Chaturbate_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
assertEquals("asdf_Stripchat_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
}
@Test
@ -158,7 +158,7 @@ class AbstractPlaceholderAwarePostProcessorTest extends AbstractPpTest {
void testMissingValueForPlaceholder() {
String input = "asdf_${modelNotes}_asdf";
when(config.getModelNotes(any())).thenReturn(null);
assertEquals("asdf__asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
assertEquals("asdf_${modelNotes}_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
}
@Test

View File

@ -7,7 +7,7 @@ import ctbrec.Settings;
import ctbrec.recorder.Recorder;
import ctbrec.recorder.RecordingManager;
import ctbrec.sites.Site;
import ctbrec.sites.chaturbate.Chaturbate;
import ctbrec.sites.stripchat.Stripchat;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@ -71,7 +71,7 @@ public abstract class AbstractPpTest {
}
Model mockModel() {
Site site = new Chaturbate();
Site site = new Stripchat();
Model model = site.createModel("Mockita Boobilicious");
model.setDisplayName("Mockita Boobilicious");
return model;

View File

@ -0,0 +1,65 @@
package ctbrec.variableexpansion;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.Settings;
import ctbrec.UnknownModel;
import ctbrec.recorder.Recorder;
import ctbrec.sites.chaturbate.Chaturbate;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
class ModelVariableExpanderTest {
Model model;
Config config;
MockedStatic<Config> configStatic;
@BeforeEach
void setup() {
UnknownModel unknownModel = new UnknownModel();
Chaturbate chaturbate = new Chaturbate();
unknownModel.setName("Pussy_Galore");
unknownModel.setDisplayName("Pussy Galore");
unknownModel.setSite(chaturbate);
this.model = unknownModel;
this.config = mockConfig();
}
@AfterEach
public void teardown() {
if (configStatic != null) {
configStatic.close();
configStatic = null;
}
}
@Test
void testMultipleVariablesAsParameter() {
Recorder recorder = mock(Recorder.class);
ModelVariableExpander modelVariableExpander = new ModelVariableExpander(model, config, recorder, null);
assertEquals("pussy_galore asdf pussy_galore", modelVariableExpander.expand("$lower(${modelName} ASDF ${modelName})"));
}
Config mockConfig() {
Config config = mock(Config.class);
Settings settings = mockSettings();
when(config.getSettings()).thenReturn(settings);
when(config.getModelNotes(any())).thenReturn("tag, foo, bar");
configStatic = mockStatic(Config.class);
configStatic.when(Config::getInstance).thenReturn(config);
return config;
}
Settings mockSettings() {
Settings settings = new Settings();
settings.recordingsDir = "/tmp/rec";
return settings;
}
}

View File

@ -24,6 +24,6 @@ class OrElseTest {
@Test
void testFallback() {
assertEquals("hello", orElse.apply("", "hello"));
assertEquals("hello", orElse.apply("asdf ${variable} asdf", "hello"));
}
}