Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 32 additions & 25 deletions junitparser/junitparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,12 @@ def text(self, value: str):
self._elem.text = value


class Skipped(Result):
class FinalResult(Result):
"""Base class for final test result (in contrast to XUnit2 RerunResult)."""

_tag = None

class Skipped(FinalResult):
"""Test result when the case is skipped."""

_tag = "skipped"
Expand All @@ -250,7 +255,7 @@ def __eq__(self, other):
return super().__eq__(other)


class Failure(Result):
class Failure(FinalResult):
"""Test result when the case failed."""

_tag = "failure"
Expand All @@ -259,7 +264,7 @@ def __eq__(self, other):
return super().__eq__(other)


class Error(Result):
class Error(FinalResult):
"""Test result when the case has errors during execution."""

_tag = "error"
Expand All @@ -268,9 +273,6 @@ def __eq__(self, other):
return super().__eq__(other)


POSSIBLE_RESULTS = {Failure, Error, Skipped}


class System(Element):
"""Parent class for :class:`SystemOut` and :class:`SystemErr`.

Expand Down Expand Up @@ -329,7 +331,7 @@ def __hash__(self):
return super().__hash__()

def __iter__(self):
all_types = set.union(POSSIBLE_RESULTS, {SystemOut}, {SystemErr})
all_types = {Failure, Error, Skipped, SystemOut, SystemErr}
for elem in self._elem.iter():
for entry_type in all_types:
if elem.tag == entry_type._tag:
Expand All @@ -344,36 +346,41 @@ def is_passed(self):
"""Whether this testcase was a success (i.e. if it isn't skipped, failed, or errored)."""
return not self.result

@property
def is_failure(self):
"""Whether this testcase failed."""
return any(isinstance(r, Failure) for r in self.result)

@property
def is_error(self):
"""Whether this testcase errored."""
return any(isinstance(r, Error) for r in self.result)

@property
def is_skipped(self):
"""Whether this testcase was skipped."""
for r in self.result:
if isinstance(r, Skipped):
return True
return False
return any(isinstance(r, Skipped) for r in self.result)

@property
def result(self):
def result(self) -> List[FinalResult]:
"""A list of :class:`Failure`, :class:`Skipped`, or :class:`Error` objects."""
results = []
for entry in self:
if isinstance(entry, tuple(POSSIBLE_RESULTS)):
results.append(entry)

return results
return [r for r in self if isinstance(r, FinalResult)]

@result.setter
def result(self, value: Union[Result, List[Result]]):
def result(self, value: Union[FinalResult, List[FinalResult]]):
# Check typing
if not (isinstance(value, FinalResult) or
isinstance(value, list) and all(isinstance(item, FinalResult) for item in value)):
raise ValueError("Value must be either FinalResult or list of FinalResult")

# First remove all existing results
for entry in self.result:
if any(isinstance(entry, r) for r in POSSIBLE_RESULTS):
self.remove(entry)
if isinstance(value, Result):
self.remove(entry)
if isinstance(value, FinalResult):
self.append(value)
elif isinstance(value, list):
else:
for entry in value:
if any(isinstance(entry, r) for r in POSSIBLE_RESULTS):
self.append(entry)
self.append(entry)

@property
def system_out(self):
Expand Down
16 changes: 9 additions & 7 deletions junitparser/xunit2.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ class StackTrace(junitparser.System):
_tag = "stackTrace"


class RerunType(junitparser.Result):
_tag = "rerunType"
class RerunResult(junitparser.Result):
"""Base class for intermediate / rerun test result (in contrast to JUnit FinalResult)."""

_tag = None

@property
def stack_trace(self):
Expand Down Expand Up @@ -157,19 +159,19 @@ def system_err(self, value: str):
self.append(err)


class RerunFailure(RerunType):
class RerunFailure(RerunResult):
_tag = "rerunFailure"


class RerunError(RerunType):
class RerunError(RerunResult):
_tag = "rerunError"


class FlakyFailure(RerunType):
class FlakyFailure(RerunResult):
_tag = "flakyFailure"


class FlakyError(RerunType):
class FlakyError(RerunResult):
_tag = "flakyError"


Expand Down Expand Up @@ -199,6 +201,6 @@ def flaky_errors(self):
"""<flakyError>"""
return self._rerun_results(FlakyError)

def add_rerun_result(self, result: RerunType):
def add_rerun_result(self, result: RerunResult):
"""Append a rerun result to the testcase. A testcase can have multiple rerun results."""
self.append(result)
14 changes: 14 additions & 0 deletions tests/test_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,18 +685,32 @@ def test_case_is_skipped(self):
case.result = [Skipped()]
assert case.is_skipped
assert not case.is_passed
assert not case.is_failure
assert not case.is_error

def test_case_is_passed(self):
case = TestCase()
case.result = []
assert not case.is_skipped
assert case.is_passed
assert not case.is_failure
assert not case.is_error

def test_case_is_failed(self):
case = TestCase()
case.result = [Failure()]
assert not case.is_skipped
assert not case.is_passed
assert case.is_failure
assert not case.is_error

def test_case_is_error(self):
case = TestCase()
case.result = [Error()]
assert not case.is_skipped
assert not case.is_passed
assert not case.is_failure
assert case.is_error


class Test_Properties:
Expand Down