2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.transform.javascript.internal;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.junit.jupiter.api.Assumptions.assumeTrue;
19 import java.io.IOException;
20 import java.nio.file.Files;
21 import java.nio.file.Path;
22 import java.nio.file.Paths;
23 import java.util.Comparator;
24 import java.util.stream.Stream;
26 import org.junit.jupiter.api.AfterEach;
27 import org.junit.jupiter.api.BeforeEach;
28 import org.junit.jupiter.api.Test;
29 import org.junit.jupiter.api.extension.ExtendWith;
30 import org.mockito.Mock;
31 import org.mockito.junit.jupiter.MockitoExtension;
32 import org.mockito.junit.jupiter.MockitoSettings;
33 import org.mockito.quality.Strictness;
34 import org.openhab.core.transform.TransformationException;
35 import org.osgi.framework.BundleContext;
38 * @author Pauli Anttila - Initial contribution
40 @ExtendWith(MockitoExtension.class)
41 @MockitoSettings(strictness = Strictness.LENIENT)
42 public class JavaScriptTransformationServiceTest {
44 private static final boolean NASHORN_AVAILABLE = isNashornAvailable();
46 private static final String BASE_FOLDER = "target";
47 private static final String SRC_FOLDER = "conf";
48 private static final String CONFIG_FOLDER = BASE_FOLDER + File.separator + SRC_FOLDER;
50 private @Mock BundleContext bundleContext;
52 private TestableJavaScriptTransformationService processor;
54 private class TestableJavaScriptTransformationService extends JavaScriptTransformationService {
55 public TestableJavaScriptTransformationService(JavaScriptEngineManager manager) {
61 * Returns if the Nashorn JavaScript engine is available based on the Java specification version property.
62 * Nashorn has been removed from JDK 15 and onwards.
64 * @return {@code true} if Nashorn is available, {@code false} otherwise
66 private static boolean isNashornAvailable() {
68 String javaVersion = System.getProperty("java.specification.version");
69 return javaVersion == null ? false : Long.parseLong(javaVersion) < 15;
70 } catch (NumberFormatException e) {
76 public void setUp() throws IOException {
77 assumeTrue(NASHORN_AVAILABLE);
79 JavaScriptEngineManager manager = new JavaScriptEngineManager();
80 processor = new TestableJavaScriptTransformationService(manager);
81 copyDirectory(SRC_FOLDER, CONFIG_FOLDER);
85 public void tearDown() throws IOException {
86 Path path = Path.of(CONFIG_FOLDER);
87 if (Files.exists(path)) {
88 try (Stream<Path> walk = Files.walk(path)) {
89 walk.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
94 private void copyDirectory(String from, String to) throws IOException {
95 Files.walk(Paths.get(from)).forEach(fromPath -> {
96 Path toPath = Paths.get(to, fromPath.toString().substring(from.length()));
98 Files.copy(fromPath, toPath);
99 } catch (IOException e) {
105 public void testInlineScript() throws Exception {
106 final String DATA = "100";
107 final String SCRIPT = "| input / 10";
109 String transformedResponse = processor.transform(SCRIPT, DATA);
110 assertEquals("10.0", transformedResponse);
114 public void testInlineScriptIncludingPipe() throws Exception {
115 final String DATA = "1";
116 final String SCRIPT = "| false || (input == '1')";
118 String transformedResponse = processor.transform(SCRIPT, DATA);
119 assertEquals("true", transformedResponse);
123 public void testReadmeExampleWithoutSubFolder() throws Exception {
124 final String DATA = "foo bar baz";
125 final String SCRIPT = "readme.js";
127 String transformedResponse = processor.transform(SCRIPT, DATA);
128 assertEquals("3", transformedResponse);
132 public void testReadmeExampleWithSubFolders() throws Exception {
133 final String DATA = "foo bar baz";
134 final String SCRIPT = "js/readme/readme.js";
136 String transformedResponse = processor.transform(SCRIPT, DATA);
137 assertEquals("3", transformedResponse);
141 public void testReadmeScaleExample() throws Exception {
142 final String DATA = "214";
143 final String SCRIPT = "scale.js?correctionFactor=1.1÷r=10.js";
145 String transformedResponse = processor.transform(SCRIPT, DATA);
146 assertEquals("23.54", transformedResponse);
150 public void testAdditionalVariables() throws Exception {
151 final String DATA = "100";
152 final String SCRIPT = "sum.js?a=10&b=1";
154 String transformedResponse = processor.transform(SCRIPT, DATA);
155 assertEquals("111", transformedResponse);
159 public void testIllegalVariableName() throws Exception {
160 final String DATA = "100";
161 final String SCRIPT = "sum.js?a=10&input=fail&b=1";
163 Exception exception = assertThrows(TransformationException.class, () -> processor.transform(SCRIPT, DATA));
164 assertEquals("'input' word is reserved and can't be used in additional parameters", exception.getMessage());
168 public void testIllegalQuestionmarkSequence() throws Exception {
169 final String DATA = "100";
170 final String SCRIPT = "sum.js?a=1&test=ab?d&b=2";
172 Exception exception = assertThrows(TransformationException.class, () -> processor.transform(SCRIPT, DATA));
173 assertEquals("Questionmark should be defined only once in the filename", exception.getMessage());
177 public void testIllegalAmbersandSequence() throws Exception {
178 final String DATA = "foo";
179 final String SCRIPT = "returntest.js?a=1&test=ab&d&b=2";
181 Exception exception = assertThrows(TransformationException.class, () -> processor.transform(SCRIPT, DATA));
182 assertEquals("Illegal filename syntax", exception.getMessage());
186 public void testEncodedSpecialCharacters() throws Exception {
187 final String DATA = "100";
188 final String SCRIPT = "returntest.js?a=1&test=ab%3Fd%26f&b=2";
190 String transformedResponse = processor.transform(SCRIPT, DATA);
191 assertEquals("ab?d&f", transformedResponse);