aboutsummaryrefslogtreecommitdiffstats
path: root/poi-excelant/src/test/java/org/apache/poi/ss/excelant/TestBuildFile.java
blob: 8e4d783348b7a842a834d8f1d754be32748d1c41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.apache.poi.ss.excelant;

import static org.apache.poi.POITestCase.assertContains;
import static org.apache.poi.POITestCase.assertNotContained;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;

import org.apache.poi.POIDataSamples;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
 *  JUnit test for the ExcelAnt tasks.
 *  Leverages Ant's test framework.
 */
public class TestBuildFile {

    protected Project project;
    private final StringBuilder logBuffer = new StringBuilder();

    @BeforeEach
    void setUp() {
        String filename = TestBuildFile.getDataDir() + "/../poi-excelant/src/test/resources/tests.xml";
        int logLevel = Project.MSG_DEBUG;
        logBuffer.setLength(0);
        project = new Project();
        project.init();
        project.setNewProperty("data.dir.name", getDataDir());
        File antFile = new File(System.getProperty("root"), filename);
        project.setUserProperty("ant.file", antFile.getAbsolutePath());
        project.addBuildListener(new AntTestListener(logLevel));
        ProjectHelper.configureProject(project, antFile);
    }

    /**
     * Automatically calls the target called "tearDown"
     * from the build file tested if it exits.
     * <p>
     * This allows to use Ant tasks directly in the build file
     * to clean up after each test. Note that no "setUp" target
     * is automatically called, since it's trivial to have a
     * test target depend on it.
     */
    @AfterEach
    void tearDown() {
        if (project == null) {
            /*
             * Maybe the BuildFileTest was subclassed and there is
             * no initialized project. So we could avoid getting a
             * NPE.
             * If there is an initialized project getTargets() does
             * not return null as it is initialized by an empty
             * HashSet.
             */
            return;
        }
        final String tearDown = "tearDown";
        if (project.getTargets().containsKey(tearDown)) {
            project.executeTarget(tearDown);
        }
    }

    /**
     * Assert that the given substring is in the log messages.
     */
    void assertLogContaining(String substring) {
        assertContains(getLog(), substring);
    }

    /**
     * Assert that the given substring is not in the log messages.
     */
    void assertLogNotContaining(String substring) {
        assertNotContained(getLog(), substring);
    }

    /**
     * Gets the log the BuildFileTest object.
     * Only valid if configureProject() has been called.
     *
     * @return The log value
     */
    public String getLog() {
        return logBuffer.toString();
    }

    /**
     * Executes a target we have set up
     *
     * @param targetName target to run
     */
    void executeTarget(String targetName) {
        project.executeTarget(targetName);
    }

    /**
     * Runs a target, wait for a build exception.
     *
     * @param target target to run
     * @param cause  information string to reader of report
     * @param msg    the message value of the build exception we are waiting
     *               for set to null for any build exception to be valid
     */
    void expectBuildException(String target, String cause, String msg) {
        BuildException be = assertThrows(BuildException.class, () -> executeTarget(target));
        if (msg != null) {
            assertEquals(msg, be.getMessage(), cause);
        }
    }

    public static String getDataDir() {
        String dataDirName = System.getProperty(POIDataSamples.TEST_PROPERTY);
        return dataDirName == null ? "test-data" : dataDirName;
    }

    /**
     * Our own personal build listener.
     */
    private class AntTestListener implements BuildListener {
        private final int logLevel;

        /**
         * Constructs a test listener which will ignore log events
         * above the given level.
         */
        public AntTestListener(int logLevel) {
            this.logLevel = logLevel;
        }

        /**
         * Fired before any targets are started.
         */
        @Override
        public void buildStarted(BuildEvent event) { }

        /**
         * Fired after the last target has finished. This event
         * will still be thrown if an error occurred during the build.
         *
         * @see BuildEvent#getException()
         */
        @Override
        public void buildFinished(BuildEvent event) { }

        /**
         * Fired when a target is started.
         *
         * @see BuildEvent#getTarget()
         */
        @Override
        public void targetStarted(BuildEvent event) { }

        /**
         * Fired when a target has finished. This event will
         * still be thrown if an error occurred during the build.
         *
         * @see BuildEvent#getException()
         */
        @Override
        public void targetFinished(BuildEvent event) { }

        /**
         * Fired when a task is started.
         *
         * @see BuildEvent#getTask()
         */
        @Override
        public void taskStarted(BuildEvent event) { }

        /**
         * Fired when a task has finished. This event will still
         * be throw if an error occurred during the build.
         *
         * @see BuildEvent#getException()
         */
        @Override
        public void taskFinished(BuildEvent event) { }

        /**
         * Fired whenever a message is logged.
         *
         * @see BuildEvent#getMessage()
         * @see BuildEvent#getPriority()
         */
        @Override
        public void messageLogged(BuildEvent event) {
            if (event.getPriority() > logLevel) {
                // ignore event
                return;
            }

            if (event.getPriority() == Project.MSG_INFO ||
                    event.getPriority() == Project.MSG_WARN ||
                    event.getPriority() == Project.MSG_ERR) {
                logBuffer.append(event.getMessage());
            }
        }
    }

    @Test
    void testMissingFilename() {
        expectBuildException("test-nofile", "required argument not specified", "fileName attribute must be set!");
    }

    @Test
    void testFileNotFound() {
        expectBuildException("test-filenotfound", "required argument not specified",
             "Cannot load file invalid.xls. Make sure the path and file permissions are correct.");
    }

    @Test
    void testEvaluate() {
        executeTarget("test-evaluate");
        assertLogContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.");
    }

    @Test
    void testEvaluateNoDetails() {
        executeTarget("test-evaluate-nodetails");
        assertLogContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogNotContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.");
    }

    @Test
    void testPrecision() {
        executeTarget("test-precision");

        assertLogContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.  " +
            "It evaluated to 2285.5761494145568 when the value of 2285.576149 with precision of 1.0E-4");
        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.  " +
            "It evaluated to 2285.5761494145568 when the value of 2285.576149 with precision of 1.0E-5");
        assertLogContaining("Failed to evaluate cell 'MortgageCalculator'!$B$4.  " +
            "It evaluated to 2285.5761494145568 when the value of 2285.576149 with precision of 1.0E-10 was expected.");
        assertLogContaining("2/3 tests passed");
    }

    @Test
    void testPrecisionFail() {
        expectBuildException("test-precision-fails", "precision not matched",
             "\tFailed to evaluate cell 'MortgageCalculator'!$B$4.  It evaluated to 2285.5761494145568 " +
             "when the value of 2285.576149 with precision of 1.0E-10 was expected.");
    }

    @Test
    void testPassOnError() {
        executeTarget("test-passonerror");
        assertLogContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogContaining("Test named failonerror failed because 1 of 0 evaluations failed to evaluate correctly.");
    }

    @Test
    void testFailOnError() {
        expectBuildException("test-failonerror", "fail on error", null);
        assertLogContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogNotContaining("failed because 1 of 0 evaluations failed to evaluate correctly. " +
            "Failed to evaluate cell 'MortageCalculatorFunction'!$D$3");
    }

    @Test
    void testFailOnErrorNoDetails() {
        expectBuildException("test-failonerror-nodetails", "fail on error", null);
        assertLogNotContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogNotContaining("failed because 1 of 0 evaluations failed to evaluate correctly. " +
            "Failed to evaluate cell 'MortageCalculatorFunction'!$D$3");
    }

    @Test
    void testUdf() {
        executeTarget("test-udf");
        assertLogContaining("1/1 tests passed");
    }

    @Test
    void testSetText() {
        executeTarget("test-settext");
        assertLogContaining("1/1 tests passed");
    }

    @Test
    void testAddHandler() {
        executeTarget("test-addhandler");
        assertLogContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.");

        assertNotNull(MockExcelAntWorkbookHandler.instance.workbook, "The workbook should have been passed to the handler");
        assertTrue(MockExcelAntWorkbookHandler.instance.executed, "The handler should have been executed");
    }

    @Test
    void testAddHandlerWrongClass() {
        executeTarget("test-addhandler-wrongclass");
        assertLogContaining("Using input file: " + TestBuildFile.getDataDir() + "/spreadsheet/excelant.xls");
        assertLogContaining("Succeeded when evaluating 'MortgageCalculator'!$B$4.");
    }

    @Test
    void testAddHandlerFails() {
        expectBuildException("test-addhandler-fails", "NullPointException", null);
    }

}