Skip to content

Commit

Permalink
ExceptionUtils class to unify exceptions format
Browse files Browse the repository at this point in the history
  • Loading branch information
HardNorth committed Nov 1, 2024
1 parent 56daf45 commit e72e2e5
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog

## [Unreleased]
### Added
- `ExceptionUtils` class to unify exceptions format, by @HardNorth
### Changed
- `MarkdownUtils`, `TemplateConfiguration` and `TemplateProcessing` was moved to `utils.formatting` package, by @HardNorth

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2024 EPAM Systems
*
* Licensed 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
*
* https://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 com.epam.reportportal.utils.formatting;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

/***
* Utility class for exception formatting.
*/
public class ExceptionUtils {
public static final String SKIP_TRACE_MARKER = "...";
public static final String LINE_DELIMITER = "\n";

/***
* Get stack trace of the throwable excluding the stack trace of the base throwable.
*
* @param throwable Throwable to get stack trace from
* @param baseThrowable Throwable to exclude stack trace from
* @param preserveCause Preserve cause in the stack trace
* @return Formatted stack trace
*/
public static String getStackTrace(Throwable throwable, Throwable baseThrowable, boolean preserveCause) {
String[] mainFrames = org.apache.commons.lang3.exception.ExceptionUtils.getStackFrames(throwable);
Set<String> baseFrames = Arrays.stream(org.apache.commons.lang3.exception.ExceptionUtils.getStackFrames(baseThrowable)).collect(
Collectors.toSet());
StringBuilder sb = new StringBuilder();
if (mainFrames.length > 0) {
sb.append(mainFrames[0]).append(LINE_DELIMITER);
boolean skipping = false;
for (int i = 1; i < mainFrames.length; i++) {
String frame = mainFrames[i];
if(baseFrames.contains(frame) && (!frame.startsWith("Caused by:") || !preserveCause)) {
if (!skipping) {
sb.append(SKIP_TRACE_MARKER);
skipping = true;
}
} else {
skipping = false;
sb.append(frame).append(LINE_DELIMITER);
}
}
}
return sb.toString();
}

/**
* Get stack trace of the throwable excluding the stack trace of the base throwable.
*
* @param throwable Throwable to get stack trace from
* @param baseThrowable Throwable to exclude stack trace from
* @return Formatted stack trace
*/
public static String getStackTrace(Throwable throwable, Throwable baseThrowable) {
return getStackTrace(throwable, baseThrowable, false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.epam.reportportal.utils.formatting;

import com.epam.reportportal.util.test.CommonUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

public class ExceptionUtilsTest {

private final ExecutorService executor = Executors.newSingleThreadExecutor();

public static void test() {
throw new IllegalStateException("This test is expected to fail");
}

public static void test2() {
throw new IllegalStateException("This test is expected to fail");
}

@AfterEach
public void tearDown() {
CommonUtils.shutdownExecutorService(executor);
}

@Test
public void test_get_stack_trace() {
Future<?> task1 = executor.submit(ExceptionUtilsTest::test);
Future<?> task2 = executor.submit(ExceptionUtilsTest::test2);
try {
task1.get();
} catch (IllegalStateException | InterruptedException | ExecutionException e) {
try {
task2.get();
} catch (IllegalStateException | InterruptedException | ExecutionException e2) {
String customStackTrace = ExceptionUtils.getStackTrace(e, e2);
String apacheStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);

String[] customFrames = customStackTrace.split("\n");
String[] apacheFrames = apacheStackTrace.split("\n");

assertThat(customFrames, arrayWithSize(lessThan(apacheFrames.length)));
assertThat(customFrames[0], equalTo(apacheFrames[0]));
assertThat(
Arrays.stream(customFrames).skip(1).collect(Collectors.toList()),
everyItem(startsWith(ExceptionUtils.SKIP_TRACE_MARKER))
);
}
}
}

@Test
public void test_get_stack_trace_with_caused_by() {
Future<?> task1 = executor.submit(ExceptionUtilsTest::test);
Future<?> task2 = executor.submit(ExceptionUtilsTest::test2);
try {
task1.get();
} catch (IllegalStateException | InterruptedException | ExecutionException e) {
try {
task2.get();
} catch (IllegalStateException | InterruptedException | ExecutionException e2) {
String customStackTrace = ExceptionUtils.getStackTrace(e, e2, true);
String apacheStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);

String[] customFrames = customStackTrace.split("\n");
String[] apacheFrames = apacheStackTrace.split("\n");

assertThat(customFrames, arrayWithSize(lessThan(apacheFrames.length)));
assertThat(customFrames[0], equalTo(apacheFrames[0]));
assertThat(customStackTrace, containsString("Caused by:"));
}
}
}
}

0 comments on commit e72e2e5

Please sign in to comment.