Skip to content

Commit dd514f7

Browse files
authored
Merge pull request #210 from metafacture/192-implementStrictMode
Implement "strict" mode.
2 parents b491cbb + e167bbe commit dd514f7

File tree

28 files changed

+375
-54
lines changed

28 files changed

+375
-54
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ package-lock.json
1212
/metafix/src/test/resources/org/metafacture/metafix/integration/**/*.err
1313
/metafix/src/test/resources/org/metafacture/metafix/integration/**/*.out
1414
/metafix/src/test/resources/org/metafacture/metafix/integration/**/output-*
15+
!/metafix/src/test/resources/org/metafacture/metafix/integration/**/expected.err

metafix/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ dependencies {
3131
implementation "org.metafacture:metamorph:${versions.metafacture}"
3232

3333
testImplementation "nl.jqno.equalsverifier:equalsverifier:${versions.equalsverifier}"
34-
testImplementation "org.mockito:mockito-core:${versions.mockito}"
34+
testImplementation "org.mockito:mockito-inline:${versions.mockito}"
3535
testImplementation "org.mockito:mockito-junit-jupiter:${versions.mockito}"
3636
}
3737

metafix/integrationTest.sh

Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ todo_file=todo.txt
1212

1313
input_glob=input.*
1414
expected_glob=expected.*
15+
expected_errors_extension=err
1516

1617
metafix_output_glob=output-metafix.*
1718
catmandu_output_glob=output-catmandu.*
@@ -102,6 +103,8 @@ function get_file() {
102103
reason="Ambiguous $type files: $*"
103104
elif [ ! -r "$1" ]; then
104105
reason="No $type file: $1"
106+
elif [ "$type" != "output" ] && [ ! -s "$1" ]; then
107+
reason="Empty $type file: $1"
105108
else
106109
current_file=$1
107110
return 0
@@ -138,6 +141,40 @@ function skip_test() {
138141
fi
139142
}
140143

144+
function test_passed() {
145+
if [ -r "$2" ]; then
146+
log "$color_test$1$color_reset: ${color_failed}FAILED$color_reset (Marked as \"to do\", but passed.)"
147+
148+
((failed++)) || true
149+
else
150+
if parse_boolean "$METAFIX_LOG_PASSED"; then
151+
log "$color_test$1$color_reset: ${color_passed}PASSED$color_reset$3"
152+
fi
153+
154+
((passed++)) || true
155+
fi
156+
}
157+
158+
function test_failed() {
159+
if ! skip_test "$1" "$2"; then
160+
log "$color_test$1$color_reset: $color_failed$4$color_reset$3"
161+
162+
if [ $# -ge 13 ]; then
163+
log " Fix: $9"
164+
log " Input: ${10}"
165+
log " Expected: ${11}"
166+
log " Output: ${12}"
167+
log " Diff: ${13}"
168+
169+
[ -s "${13}" ] && $colordiff <"${13}" || rm -f "${13}"
170+
fi
171+
172+
command_info "$5" "$6" "$7" "$8"
173+
174+
((failed++)) || true
175+
fi
176+
}
177+
141178
function run_tests() {
142179
local test matched=1\
143180
test_directory test_fix test_input test_expected test_todo\
@@ -165,62 +202,51 @@ function run_tests() {
165202
test_todo="$test_directory/$todo_file"
166203

167204
if [ -z "$disable_todo" ] || ! skip_test "$test" "$test_todo"; then
205+
# TODO: catmandu (optional)
206+
168207
metafix_command_output="$test_directory/metafix.out"
169208
metafix_command_error="$test_directory/metafix.err"
170209

171210
metafix_start_time=$(current_time)
172211

173-
# TODO: catmandu (optional)
212+
run_metafix "$test_directory/$metafix_file" >"$metafix_command_output" 2>"$metafix_command_error"
213+
metafix_exit_status=$?
174214

175-
if run_metafix "$test_directory/$metafix_file" >"$metafix_command_output" 2>"$metafix_command_error"; then
176-
metafix_exit_status=$?
215+
metafix_elapsed_time=$(elapsed_time "$metafix_start_time")
177216

217+
if [ "$metafix_exit_status" -eq 0 ]; then
178218
if get_file "$test" output "$test_directory"/$metafix_output_glob; then
179219
metafix_output=$current_file
180220
metafix_diff="$test_directory/metafix.diff"
181221

182-
metafix_elapsed_time=$(elapsed_time "$metafix_start_time")
183-
184222
if diff -u "$test_expected" "$metafix_output" >"$metafix_diff"; then
185-
if [ -r "$test_todo" ]; then
186-
log "$color_test$test$color_reset: ${color_failed}FAILED$color_reset (Marked as \"to do\", but passed.)"
187-
188-
((failed++)) || true
189-
else
190-
if parse_boolean "$METAFIX_LOG_PASSED"; then
191-
log "$color_test$test$color_reset: ${color_passed}PASSED$color_reset$metafix_elapsed_time"
192-
fi
193-
194-
((passed++)) || true
195-
fi
223+
test_passed "$test" "$test_todo" "$metafix_elapsed_time"
196224

197225
rm -f "$metafix_diff" "$metafix_command_output" "$metafix_command_error"
198-
elif ! skip_test "$test" "$test_todo"; then
199-
log "$color_test$test$color_reset: ${color_failed}FAILED$color_reset$metafix_elapsed_time"
200-
201-
log " Fix: $test_fix"
202-
log " Input: $test_input"
203-
log " Expected: $test_expected"
204-
log " Output: $metafix_output"
205-
log " Diff: $metafix_diff"
206-
207-
[ -s "$metafix_diff" ] && $colordiff <"$metafix_diff" || rm -f "$metafix_diff"
208-
209-
command_info metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
210-
211-
((failed++)) || true
226+
else
227+
test_failed "$test" "$test_todo" "$metafix_elapsed_time" FAILED\
228+
metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"\
229+
"$test_fix" "$test_input" "$test_expected" "$metafix_output" "$metafix_diff"
212230
fi
213231
else
214232
command_info metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
215233
fi
216-
elif ! skip_test "$test" "$test_todo"; then
217-
metafix_exit_status=$?
234+
elif [ "${test_expected##*.}" == "$expected_errors_extension" ]; then
235+
get_file "$test" error "$metafix_command_error" || { log; continue; }
218236

219-
log "$color_test$test$color_reset: ${color_error}ERROR$color_reset"
237+
while read -r pattern; do
238+
if ! grep -qE "$pattern" "$metafix_command_error"; then
239+
test_failed "$test" "$test_todo" " (Pattern not found: $pattern)" FAILED\
240+
metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
220241

221-
command_info metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
242+
continue 2
243+
fi
244+
done <"$test_expected"
222245

223-
((failed++)) || true
246+
test_passed "$test" "$test_todo" "$metafix_elapsed_time"
247+
else
248+
test_failed "$test" "$test_todo" "$metafix_elapsed_time" ERROR\
249+
metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
224250
fi
225251
fi
226252
done

metafix/src/main/java/org/metafacture/metafix/FixExecutionException.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818

1919
import org.metafacture.framework.MetafactureException;
2020

21+
/**
22+
* Indicates dynamic (i.e., data-dependent) issues during Fix execution that
23+
* should be subject to {@link Metafix.Strictness strictness} handling.
24+
*
25+
* @see FixProcessException
26+
*/
2127
public class FixExecutionException extends MetafactureException {
2228

2329
public FixExecutionException(final String message) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2022 hbz NRW
3+
*
4+
* Licensed under the Apache License, Version 2.0 the "License";
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.metafacture.metafix;
18+
19+
import org.metafacture.framework.MetafactureException;
20+
21+
/**
22+
* Indicates static (i.e., data-independent) issues with the usage of Fix
23+
* expressions.
24+
*
25+
* @see FixExecutionException
26+
*/
27+
public class FixProcessException extends MetafactureException {
28+
29+
public FixProcessException(final String message) {
30+
super(message);
31+
}
32+
33+
public FixProcessException(final String message, final Throwable cause) {
34+
super(message, cause);
35+
}
36+
37+
}

metafix/src/main/java/org/metafacture/metafix/Metafix.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.LinkedList;
4646
import java.util.List;
4747
import java.util.Map;
48+
import java.util.function.BiConsumer;
4849

4950
/**
5051
* Transforms a data stream sent via the {@link StreamReceiver} interface. Use
@@ -61,6 +62,8 @@ public class Metafix implements StreamPipe<StreamReceiver>, Maps { // checkstyle
6162
public static final String VAR_END = "]";
6263
public static final String VAR_START = "$[";
6364

65+
public static final Strictness DEFAULT_STRICTNESS = Strictness.PROCESS;
66+
6467
public static final Map<String, String> NO_VARS = Collections.emptyMap();
6568

6669
private static final Logger LOG = LoggerFactory.getLogger(Metafix.class);
@@ -79,6 +82,7 @@ public class Metafix implements StreamPipe<StreamReceiver>, Maps { // checkstyle
7982
private List<Value> entities = new ArrayList<>();
8083
private Record currentRecord = new Record();
8184
private StreamReceiver outputStreamReceiver;
85+
private Strictness strictness = DEFAULT_STRICTNESS;
8286
private String fixFile;
8387
private String recordIdentifier;
8488
private int entityCount;
@@ -325,4 +329,58 @@ public String putValue(final String mapName, final String key, final String valu
325329
return maps.computeIfAbsent(mapName, k -> new HashMap<>()).put(key, value);
326330
}
327331

332+
public void setStrictness(final Strictness strictness) {
333+
this.strictness = strictness != null ? strictness : DEFAULT_STRICTNESS;
334+
}
335+
336+
public Strictness getStrictness() {
337+
return strictness;
338+
}
339+
340+
public enum Strictness {
341+
342+
/**
343+
* Aborts process by throwing an exception.
344+
*/
345+
PROCESS {
346+
@Override
347+
protected void handleInternal(final FixExecutionException exception, final Record record) {
348+
throw exception;
349+
}
350+
},
351+
352+
/**
353+
* Ignores (skips) record and logs an error.
354+
*/
355+
RECORD {
356+
@Override
357+
protected void handleInternal(final FixExecutionException exception, final Record record) {
358+
log(exception, LOG::error);
359+
record.setReject(true); // TODO: Skip remaining expressions?
360+
}
361+
},
362+
363+
/**
364+
* Ignores (skips) expression and logs a warning.
365+
*/
366+
EXPRESSION {
367+
@Override
368+
protected void handleInternal(final FixExecutionException exception, final Record record) {
369+
log(exception, LOG::warn);
370+
}
371+
};
372+
373+
public void handle(final FixExecutionException exception, final Record record) {
374+
LOG.debug("Current record: {}", record);
375+
handleInternal(exception, record);
376+
}
377+
378+
protected abstract void handleInternal(FixExecutionException exception, Record record);
379+
380+
protected void log(final FixExecutionException exception, final BiConsumer<String, Throwable> logger) {
381+
logger.accept(exception.getMessage(), exception.getCause());
382+
}
383+
384+
}
385+
328386
}

metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ else if (e instanceof MethodCall) {
9898
processFunction((MethodCall) e, params);
9999
}
100100
else {
101-
throw new FixExecutionException(executionExceptionMessage(e));
101+
throw new FixProcessException(executionExceptionMessage(e));
102102
}
103103
});
104104
}
@@ -173,15 +173,26 @@ private void processExpression(final Expression expression, final Consumer<Strin
173173
}
174174

175175
private void processFix(final Supplier<String> messageSupplier, final Runnable runnable) {
176+
final FixExecutionException exception;
177+
176178
try {
177179
runnable.run();
180+
return;
178181
}
179-
catch (final FixExecutionException e) {
182+
catch (final FixProcessException e) {
180183
throw e; // TODO: Add nesting information?
181184
}
185+
catch (final FixExecutionException e) {
186+
exception = e; // TODO: Add nesting information?
187+
}
188+
catch (final IllegalStateException | NumberFormatException e) {
189+
exception = new FixExecutionException(messageSupplier.get(), e);
190+
}
182191
catch (final RuntimeException e) { // checkstyle-disable-line IllegalCatch
183-
throw new FixExecutionException(messageSupplier.get(), e);
192+
throw new FixProcessException(messageSupplier.get(), e);
184193
}
194+
195+
metafix.getStrictness().handle(exception, record);
185196
}
186197

187198
private String executionExceptionMessage(final Expression expression) {

metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public void shouldLookupInSeparateExternalFileMap() {
159159
public void shouldNotLookupInRelativeExternalFileMapFromInlineScript() {
160160
final String mapFile = "../maps/test.csv";
161161

162-
MetafixTestHelpers.assertThrowsCause(IllegalArgumentException.class, "Cannot resolve relative path: " + mapFile, () ->
162+
MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "Cannot resolve relative path: " + mapFile, () ->
163163
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
164164
LOOKUP + " '" + mapFile + "')"
165165
),
@@ -299,7 +299,7 @@ public void shouldNotLookupInUnknownInternalMap() {
299299

300300
@Test
301301
public void shouldFailLookupInUnknownExternalMap() {
302-
MetafixTestHelpers.assertThrowsCause(MorphExecutionException.class, "File not found: testMap.csv", () ->
302+
MetafixTestHelpers.assertProcessException(MorphExecutionException.class, "File not found: testMap.csv", () ->
303303
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
304304
LOOKUP + " 'testMap.csv')"
305305
),

0 commit comments

Comments
 (0)