ExactMatch and Contains share identical logic in two places:
1. validate() — case-insensitive comparison pattern:
if self.case_sensitive:
passed = response == self.expected # or: self.substring in response
else:
passed = response.lower() == self.expected.lower()
This block is copy-pasted verbatim in both classes.
2. describe() — mode label string:
mode = "case-sensitive" if self.case_sensitive else "case-insensitive"
This expression is identical in both ExactMatch.describe() and Contains.describe().
Any change to the case-insensitive comparison logic or the mode label must be applied in two separate places.
ExactMatchandContainsshare identical logic in two places:1.
validate()— case-insensitive comparison pattern:This block is copy-pasted verbatim in both classes.
2.
describe()— mode label string:This expression is identical in both
ExactMatch.describe()andContains.describe().Any change to the case-insensitive comparison logic or the mode label must be applied in two separate places.