├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug.md │ └── feature.md ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── build-project.yml │ ├── deploy-release.yml │ ├── release-beta.yml │ ├── release-feature-finish.yml │ ├── release-feature-start.yml │ ├── release-hotfix-finish.yml │ └── release-hotfix-start.yml ├── .gitignore ├── .mergify.yml ├── .retest ├── recheck.ignore ├── recheck.ignore.js ├── recheck.js.ignore └── retest.properties ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── de │ │ └── retest │ │ └── recheck │ │ ├── ExecutingTestContext.java │ │ ├── FileNamerStrategy.java │ │ ├── GradleConformFileNamerStrategy.java │ │ ├── MavenConformFileNamerStrategy.java │ │ ├── NoGoldenMasterActionReplayResult.java │ │ ├── Recheck.java │ │ ├── RecheckAdapter.java │ │ ├── RecheckCapMessage.java │ │ ├── RecheckImpl.java │ │ ├── RecheckLifecycle.java │ │ ├── RecheckOptions.java │ │ ├── RecheckProperties.java │ │ ├── Rehub.java │ │ ├── SuiteAggregator.java │ │ ├── SutStateLoader.java │ │ ├── TestCaseFinder.java │ │ ├── XmlTransformerUtil.java │ │ ├── auth │ │ ├── AuthenticationHandler.java │ │ ├── DefaultAuthenticationHandler.java │ │ ├── KeycloakResult.java │ │ ├── RehubAuthenticationHandler.java │ │ ├── RetestAuthentication.java │ │ └── UnableToAuthenticateOfflineException.java │ │ ├── configuration │ │ ├── PathBasedProjectRootFinder.java │ │ ├── ProjectConfiguration.java │ │ ├── ProjectConfigurationUtil.java │ │ ├── ProjectRootFinder.java │ │ └── ProjectRootFinderUtil.java │ │ ├── execution │ │ ├── RecheckAdapters.java │ │ └── RecheckDifferenceFinder.java │ │ ├── ignore │ │ ├── AllMatchFilter.java │ │ ├── CacheFilter.java │ │ ├── CompoundFilter.java │ │ ├── Filter.java │ │ ├── FilterAllAttributes.java │ │ ├── FilterLoader.java │ │ ├── FilterNotFoundException.java │ │ ├── FilterOutline.java │ │ ├── Filters.java │ │ ├── GloballyIgnoredAttributes.java │ │ ├── JSFilterImpl.java │ │ ├── PersistentFilter.java │ │ ├── RecheckIgnoreLocator.java │ │ ├── RecheckIgnoreUtil.java │ │ ├── SearchFilterFiles.java │ │ └── ShouldIgnore.java │ │ ├── image │ │ ├── ExactImageDifferenceCalculator.java │ │ ├── FuzzyImageDifferenceCalculator.java │ │ ├── ImageDiffCalcFactory.java │ │ ├── ImageDifference.java │ │ └── ImageDifferenceCalculator.java │ │ ├── ioerror │ │ ├── ReTestIOException.java │ │ ├── ReTestLoadException.java │ │ └── ReTestSaveException.java │ │ ├── meta │ │ ├── GlobalMetadataProvider.java │ │ ├── MetadataProvider.java │ │ ├── MetadataProviderService.java │ │ ├── MultiMetadataProvider.java │ │ └── global │ │ │ ├── GitMetadataProvider.java │ │ │ ├── MachineMetadataProvider.java │ │ │ ├── OSMetadataProvider.java │ │ │ └── TimeMetadataProvider.java │ │ ├── persistence │ │ ├── ClassAndMethodBasedNamingStrategy.java │ │ ├── ClassAndMethodBasedShortNamingStrategy.java │ │ ├── CloudPersistence.java │ │ ├── DateAdapter.java │ │ ├── ExplicitMutableNamingStrategy.java │ │ ├── FileNamer.java │ │ ├── FileOutputFormat.java │ │ ├── GitExecutor.java │ │ ├── GoldenMasterProvider.java │ │ ├── GoldenMasterProviderImpl.java │ │ ├── GoldenMasterSourceSuppressDefaultAdapter.java │ │ ├── GradleProjectLayout.java │ │ ├── IncompatibleReportVersionException.java │ │ ├── MavenProjectLayout.java │ │ ├── NamingStrategy.java │ │ ├── NoGoldenMasterFoundException.java │ │ ├── Persistable.java │ │ ├── Persistence.java │ │ ├── PersistenceFactory.java │ │ ├── ProjectLayout.java │ │ ├── ProjectLayouts.java │ │ ├── RecheckSutState.java │ │ ├── RecheckTestReportUtil.java │ │ ├── SeparatePathsProjectLayout.java │ │ ├── bin │ │ │ ├── KryoPersistence.java │ │ │ └── KryoRegister.java │ │ ├── migration │ │ │ ├── MigrationPairs.java │ │ │ ├── RemoveElementTransformer.java │ │ │ ├── RenameElementTransformer.java │ │ │ ├── ReplaceAttributeTransformer.java │ │ │ ├── XmlMigrator.java │ │ │ ├── XmlMigratorInstances.java │ │ │ ├── XmlTransformer.java │ │ │ └── transformers │ │ │ │ ├── AddRetestIdTestTransformer.java │ │ │ │ ├── ContainedComponents2ContainedElementsTransformer.java │ │ │ │ ├── IncompatibleChangesTransformer.java │ │ │ │ ├── Path2XPathTransformer.java │ │ │ │ ├── PathAndType2LowerCaseTransformer.java │ │ │ │ └── WindowSuffixTransformer.java │ │ └── xml │ │ │ ├── ReTestXmlDataContainer.java │ │ │ ├── XmlFolderPersistence.java │ │ │ ├── XmlPersistenceUtil.java │ │ │ ├── XmlTransformer.java │ │ │ ├── XmlTransformerConfiguration.java │ │ │ ├── XmlZipPersistence.java │ │ │ └── util │ │ │ ├── LazyScreenshotZipPersistence.java │ │ │ ├── ScreenshotFolderPersistence.java │ │ │ ├── SessionLogDelegate.java │ │ │ ├── StdXmlClassesProvider.java │ │ │ ├── XmlUtil.java │ │ │ └── XmlVersionCheckResult.java │ │ ├── printer │ │ ├── ActionReplayResultPrinter.java │ │ ├── AttributeDifferencePrinter.java │ │ ├── AttributesDifferencePrinter.java │ │ ├── DefaultValueFinderProvider.java │ │ ├── ElementDifferencePrinter.java │ │ ├── InsertedDeletedElementDifferencePrinter.java │ │ ├── MetadataDifferencePrinter.java │ │ ├── Printer.java │ │ ├── SuiteReplayResultPrinter.java │ │ ├── TestReplayResultPrinter.java │ │ ├── TestReportPrinter.java │ │ └── highlighting │ │ │ ├── DefaultHighlighter.java │ │ │ ├── HighlightType.java │ │ │ ├── Highlighter.java │ │ │ └── UnsupportedHighlightTypeException.java │ │ ├── report │ │ ├── ActionReplayResult.java │ │ ├── MetadataDifferenceFilter.java │ │ ├── SuiteReplayResult.java │ │ ├── TestReplayResult.java │ │ ├── TestReport.java │ │ ├── TestReportFilter.java │ │ └── action │ │ │ ├── ActionReplayData.java │ │ │ ├── DifferenceRetriever.java │ │ │ └── WindowRetriever.java │ │ ├── review │ │ ├── GlobalChangeSetApplier.java │ │ ├── GlobalIgnoreApplier.java │ │ ├── counter │ │ │ ├── Counter.java │ │ │ ├── IntCounter.java │ │ │ └── NopCounter.java │ │ ├── ignore │ │ │ ├── AttributeFilter.java │ │ │ ├── AttributeRegexFilter.java │ │ │ ├── ChainableFilterLoaderUtil.java │ │ │ ├── ColorDiffFilter.java │ │ │ ├── DeletedFilter.java │ │ │ ├── ElementFilter.java │ │ │ ├── ExcludeFilter.java │ │ │ ├── FilterPreserveLineLoader.java │ │ │ ├── ImportedExternalFilter.java │ │ │ ├── InsertedFilter.java │ │ │ ├── JSFilterLoader.java │ │ │ ├── MatcherFilter.java │ │ │ ├── PixelDiffFilter.java │ │ │ ├── ValueRegexFilter.java │ │ │ ├── io │ │ │ │ ├── ErrorHandlingLoader.java │ │ │ │ ├── ImportExternalFilterLoader.java │ │ │ │ ├── InheritanceLoader.java │ │ │ │ ├── Loader.java │ │ │ │ ├── Loaders.java │ │ │ │ └── RegexLoader.java │ │ │ └── matcher │ │ │ │ ├── ElementByAttributeMatcher.java │ │ │ │ ├── ElementClassMatcher.java │ │ │ │ ├── ElementIdMatcher.java │ │ │ │ ├── ElementRetestIdMatcher.java │ │ │ │ ├── ElementTypeMatcher.java │ │ │ │ ├── ElementXPathMatcher.java │ │ │ │ └── Matcher.java │ │ └── workers │ │ │ ├── LoadFilterWorker.java │ │ │ └── SaveFilterWorker.java │ │ ├── suite │ │ ├── CapturedSuite.java │ │ ├── ExecutableSuite.java │ │ ├── ExecutionSuitesDoNotMatchException.java │ │ └── flow │ │ │ ├── ApplyChangesToStatesFlow.java │ │ │ └── CreateChangesetForAllDifferencesFlow.java │ │ ├── test │ │ └── Test.java │ │ ├── ui │ │ ├── DefaultValueFinder.java │ │ ├── Environment.java │ │ ├── IgnoredTypes.java │ │ ├── Path.java │ │ ├── PathAdapter.java │ │ ├── PathElement.java │ │ ├── TargetFinder.java │ │ ├── actions │ │ │ ├── AbstractAction.java │ │ │ ├── Action.java │ │ │ ├── ActionExecutionResult.java │ │ │ ├── ActionList.java │ │ │ ├── ActionParameter.java │ │ │ ├── ActionSequence.java │ │ │ ├── ActionState.java │ │ │ ├── ActionStateSequence.java │ │ │ ├── Actions.java │ │ │ ├── ExceptionWrapper.java │ │ │ ├── ParameterizedAction.java │ │ │ ├── TargetNotFoundException.java │ │ │ ├── TargetNotFoundWrapper.java │ │ │ └── ValueProvider.java │ │ ├── components │ │ │ ├── Component.java │ │ │ ├── ComponentContainer.java │ │ │ └── RootContainer.java │ │ ├── descriptors │ │ │ ├── AdditionalAttributeDifference.java │ │ │ ├── Attribute.java │ │ │ ├── AttributeUtil.java │ │ │ ├── Attributes.java │ │ │ ├── AttributesAdapter.java │ │ │ ├── CodeLocAttribute.java │ │ │ ├── ContextAttribute.java │ │ │ ├── DefaultAttribute.java │ │ │ ├── Element.java │ │ │ ├── ElementUtil.java │ │ │ ├── GroundState.java │ │ │ ├── IdentifyingAttributes.java │ │ │ ├── IdentifyingAttributesAdapter.java │ │ │ ├── MutableAttributes.java │ │ │ ├── OutlineAttribute.java │ │ │ ├── ParameterParseException.java │ │ │ ├── ParameterType.java │ │ │ ├── ParameterizedAttribute.java │ │ │ ├── ParseStringAttributeDifference.java │ │ │ ├── PathAttribute.java │ │ │ ├── RenderContainedElementsAdapter.java │ │ │ ├── RootElement.java │ │ │ ├── ScreenshotAttributeDifference.java │ │ │ ├── StateAttributesAdapter.java │ │ │ ├── StringAttribute.java │ │ │ ├── SuffixAttribute.java │ │ │ ├── SutState.java │ │ │ ├── SutStateFilter.java │ │ │ ├── TextAttribute.java │ │ │ ├── VariableNameAttributeDifference.java │ │ │ ├── WeightedTextAttribute.java │ │ │ └── idproviders │ │ │ │ ├── AbstractFirstNonNullRetestIdProvider.java │ │ │ │ ├── ConsistentRetestIdProvider.java │ │ │ │ ├── DefaultRetestIdProvider.java │ │ │ │ ├── ElementCountingRetestIdProvider.java │ │ │ │ └── RetestIdProvider.java │ │ ├── diff │ │ │ ├── Alignment.java │ │ │ ├── AlignmentPseudoElementHack.java │ │ │ ├── AttributeDifference.java │ │ │ ├── AttributesDifference.java │ │ │ ├── AttributesDifferenceFinder.java │ │ │ ├── Difference.java │ │ │ ├── ElementDifference.java │ │ │ ├── ElementDifferenceFinder.java │ │ │ ├── ElementIdentificationWarning.java │ │ │ ├── IdentifyingAttributesDifference.java │ │ │ ├── IdentifyingAttributesDifferenceFinder.java │ │ │ ├── InsertedDeletedElementDifference.java │ │ │ ├── LeafDifference.java │ │ │ ├── Match.java │ │ │ ├── RootElementDifference.java │ │ │ ├── RootElementDifferenceFinder.java │ │ │ ├── StateDifference.java │ │ │ └── meta │ │ │ │ ├── MetadataDifference.java │ │ │ │ ├── MetadataDifferenceFinder.java │ │ │ │ └── MetadataElementDifference.java │ │ ├── image │ │ │ ├── ImageUtils.java │ │ │ └── Screenshot.java │ │ └── review │ │ │ ├── ActionChangeSet.java │ │ │ ├── AttributeChanges.java │ │ │ ├── GoldenMasterSource.java │ │ │ ├── ReviewResult.java │ │ │ ├── ScreenshotChanges.java │ │ │ ├── SuiteChangeSet.java │ │ │ └── TestChangeSet.java │ │ └── util │ │ ├── ChecksumCalculator.java │ │ ├── DeleteOnCloseFileInputStream.java │ │ ├── ExceptionUtil.java │ │ ├── FileUtil.java │ │ ├── GetRelativeFilePath.java │ │ ├── JvmUtil.java │ │ ├── ListMap.java │ │ ├── ListSet.java │ │ ├── NamedBufferedInputStream.java │ │ ├── ObjectUtil.java │ │ ├── OptionalUtil.java │ │ ├── Predicates.java │ │ ├── ReflectionUtilities.java │ │ ├── RetestIdProviderUtil.java │ │ ├── RetestIdUtil.java │ │ ├── StackTraceParser.java │ │ ├── StringSimilarity.java │ │ ├── ThreadUtil.java │ │ └── VersionProvider.java └── resources │ ├── default-recheck.ignore │ ├── default-recheck.ignore.js │ ├── default-retest.properties │ ├── filter │ ├── metadata.filter │ ├── volatile-metadata.filter │ └── web │ │ ├── content.filter │ │ ├── invisible-attributes.filter │ │ ├── positioning.filter │ │ └── style-attributes.filter │ └── retest-defaults.properties └── test ├── java ├── DefaultRecheckIgnoreJsTest.java ├── DefaultRecheckIgnoreTest.java └── de │ └── retest │ ├── recheck │ ├── FileNamerStrategyTest.java │ ├── GradleConformFileNamerStrategyTest.java │ ├── LegacyCompatibilityFileNamerStrategyTest.java │ ├── MavenConformFileNamerStrategyTest.java │ ├── NoGoldenMasterActionReplayResultTest.java │ ├── RecheckCapMessageTest.java │ ├── RecheckImplIT.java │ ├── RecheckImplTest.java │ ├── RecheckOptionsIT.java │ ├── RecheckOptionsTest.java │ ├── RecheckPropertiesTest.java │ ├── SuiteAggregatorTest.java │ ├── TestCaseFinderJunitJupiterTest.java │ ├── TestCaseFinderJunitVintageTest.java │ ├── TestCaseFinderJunitVintageTheoryTest.java │ ├── TestCaseFinderTest.java │ ├── auth │ │ └── RetestAuthenticationTest.java │ ├── configuration │ │ ├── ProjectConfigurationTest.java │ │ └── ProjectRootFinderTest.java │ ├── execution │ │ ├── RecheckAdaptersTest.java │ │ └── RecheckDifferenceFinderTest.java │ ├── ignore │ │ ├── AllMatchFilterLoaderTest.java │ │ ├── AllMatchFilterTest.java │ │ ├── CacheFilterTest.java │ │ ├── CompoundFilterTest.java │ │ ├── ContentFilterIT.java │ │ ├── FilterLoaderTest.java │ │ ├── FiltersIT.java │ │ ├── FiltersTest.java │ │ ├── GloballyIgnoredAttributesTest.java │ │ ├── JSFilterImplTest.java │ │ ├── SearchFilterFilesIT.java │ │ └── SearchFilterFilesTest.java │ ├── image │ │ ├── ExactImageDifferenceCalculatorTest.java │ │ ├── FuzzyImageDifferenceCalculatorTest.java │ │ └── ImageCompare.java │ ├── meta │ │ ├── GlobalMetadataProviderTest.java │ │ ├── MetadataProviderServiceTest.java │ │ ├── MultiMetadataProviderTest.java │ │ └── global │ │ │ ├── GitMetadataProviderTest.java │ │ │ ├── OSMetadataProviderTest.java │ │ │ └── TimeMetadataProviderTest.java │ ├── persistence │ │ ├── ClassAndMethodBasedNamingStrategyTest.java │ │ ├── ClassAndMethodBasedShortNamingStrategyTest.java │ │ ├── DateAdapterTest.java │ │ ├── GitExecutorTest.java │ │ ├── GoldenMasterProviderImplTest.java │ │ ├── GradleProjectLayoutTest.java │ │ ├── MavenConformFileNamerTest.java │ │ ├── MavenProjectLayoutTest.java │ │ ├── NoGoldenMasterFoundExceptionTest.java │ │ ├── PersistenceFactoryTest.java │ │ ├── ProjectLayoutsIT.java │ │ ├── RecheckSutStateTest.java │ │ ├── RecheckTestReportUtilTest.java │ │ ├── bin │ │ │ └── KryoPersistenceTest.java │ │ ├── migration │ │ │ ├── RemoveElementTransformerIT.java │ │ │ ├── XmlMigratorIT.java │ │ │ ├── XmlMigratorInstancesTest.java │ │ │ └── transformers │ │ │ │ ├── AddRetestIdTestTransformerIT.java │ │ │ │ ├── Path2XPathTransformerIT.java │ │ │ │ ├── PathAndType2LowerCaseTransformerIT.java │ │ │ │ └── WindowSuffixTransformerIT.java │ │ └── xml │ │ │ ├── ReTestXmlDataContainerTest.java │ │ │ ├── TestPersistable.java │ │ │ ├── XmlFolderPersistenceTest.java │ │ │ ├── XmlTransformerTest.java │ │ │ ├── XmlZipPersistenceTest.java │ │ │ └── util │ │ │ ├── LazyScreenshotZipPersistenceTest.java │ │ │ ├── ScreenshotFolderPersistenceTest.java │ │ │ ├── ScreenshotTransformerTestJaxbClass.java │ │ │ └── XmlVersionCheckResultTest.java │ ├── printer │ │ ├── ActionReplayResultPrinterTest.java │ │ ├── AttributeDifferencePrinterTest.java │ │ ├── AttributesDifferencePrinterTest.java │ │ ├── ElementDifferencePrinterTest.java │ │ ├── InsertedDeletedElementDifferencePrinterTest.java │ │ ├── MetadataDifferencePrinterTest.java │ │ ├── SuiteReplayResultPrinterTest.java │ │ ├── SuiteReplayResultTest.java │ │ ├── TestReplayResultPrinterTest.java │ │ └── TestReportPrinterTest.java │ ├── report │ │ ├── ActionReplayResultTest.java │ │ ├── MetadataDifferenceFilterTest.java │ │ ├── TestReplayResultTest.java │ │ └── TestReportFilterTest.java │ ├── review │ │ ├── GlobalChangeSetApplierIT.java │ │ ├── GlobalChangeSetApplierTest.java │ │ ├── GlobalIgnoreApplierTest.java │ │ ├── ignore │ │ │ ├── AttributeFilterLoaderTest.java │ │ │ ├── AttributeFilterTest.java │ │ │ ├── AttributeRegexFilterLoaderTest.java │ │ │ ├── AttributeRegexFilterTest.java │ │ │ ├── ColorDiffFilterLoaderTest.java │ │ │ ├── ColorDiffFilterTest.java │ │ │ ├── DeletedFilterTest.java │ │ │ ├── ExcludeFilterIT.java │ │ │ ├── ExcludeFilterTest.java │ │ │ ├── FilterPreserveLineTest.java │ │ │ ├── InsertedFilterTest.java │ │ │ ├── MatcherFilterIT.java │ │ │ ├── MatcherFilterLoaderTest.java │ │ │ ├── MatcherFilterTest.java │ │ │ ├── PixelDiffFilterLoaderTest.java │ │ │ ├── PixelDiffFilterTest.java │ │ │ ├── RegexAttributeFilterTest.java │ │ │ ├── ValueRegexFilterTest.java │ │ │ ├── io │ │ │ │ ├── ImportExternalFilterLoaderIT.java │ │ │ │ ├── InheritanceLoaderTest.java │ │ │ │ └── LoaderTest.java │ │ │ └── matcher │ │ │ │ ├── ElementByAttributeMatcherTest.java │ │ │ │ ├── ElementClassMatcherLoaderTest.java │ │ │ │ ├── ElementClassMatcherTest.java │ │ │ │ ├── ElementIdMatcherLoaderTest.java │ │ │ │ ├── ElementIdMatcherTest.java │ │ │ │ ├── ElementRetestIdMatcherLoaderTest.java │ │ │ │ ├── ElementRetestIdMatcherTest.java │ │ │ │ ├── ElementTypeMatcherTest.java │ │ │ │ └── ElementXPathMatcherTest.java │ │ └── workers │ │ │ ├── LoadAndSaveFilterWorkerTest.java │ │ │ ├── LoadFilterWorkerTest.java │ │ │ ├── MigrateIgnoreFileTest.java │ │ │ └── SaveFilterWorkerIT.java │ ├── ui │ │ ├── PathElementTest.java │ │ ├── PathTest.java │ │ ├── TargetFinderTest.java │ │ ├── actions │ │ │ ├── AbstractActionImplTest.java │ │ │ ├── AbstractActionImpl_execute_Test.java │ │ │ ├── ActionsTest.java │ │ │ ├── ExceptionWrapperTest.java │ │ │ ├── ParameterizedActionTest.java │ │ │ └── TargetNotFoundExceptionTest.java │ │ ├── descriptors │ │ │ ├── ActionChangeSetTestUtils.java │ │ │ ├── AttributeImplPersistenceTest.java │ │ │ ├── AttributeImplTest.java │ │ │ ├── AttributeUtilTest.java │ │ │ ├── AttributesTest.java │ │ │ ├── DefaultAttributeTest.java │ │ │ ├── ElementIT.java │ │ │ ├── ElementTest.java │ │ │ ├── ElementUtilTest.java │ │ │ ├── IdentifyingAttributesTest.java │ │ │ ├── IdentifyingAttributes_proprietary_Test.java │ │ │ ├── OutlineAttributeTest.java │ │ │ ├── ParseStringAttributeDifferenceTest.java │ │ │ ├── PathAttributeTest.java │ │ │ ├── RenderContainedElementsAdapterTest.java │ │ │ ├── RootElementTest.java │ │ │ ├── StringAttributeTest.java │ │ │ ├── SutStateFilterTest.java │ │ │ ├── SutStateTest.java │ │ │ ├── TextAttributeTest.java │ │ │ ├── VariableNameAttributeDifferenceIntTest.java │ │ │ ├── VariableNameAttributeDifferenceTest.java │ │ │ └── idproviders │ │ │ │ ├── ConsistentRetestIdProviderTest.java │ │ │ │ ├── DefaultRetestIdProviderTest.java │ │ │ │ └── ElementCountingRetestIdProviderTest.java │ │ ├── diff │ │ │ ├── AlignmentTest.java │ │ │ ├── AttributeDifferenceTest.java │ │ │ ├── AttributesDifferenceFinderTest.java │ │ │ ├── ElementBuilder.java │ │ │ ├── ElementDifferenceAdapter.java │ │ │ ├── ElementDifferenceFinderTest.java │ │ │ ├── ElementDifferenceTest.java │ │ │ ├── IdentifyingAttributesDifferenceFinderTest.java │ │ │ ├── InsertedDeletedElementDifferenceTest.java │ │ │ ├── MatchTest.java │ │ │ ├── RootElementDifferenceFinderTest.java │ │ │ ├── RootElementDifferenceTest.java │ │ │ ├── StateDifferenceTest.java │ │ │ └── meta │ │ │ │ ├── MetadataDifferenceFinderTest.java │ │ │ │ └── MetadataDifferenceTest.java │ │ ├── image │ │ │ ├── ImageUtilsTest.java │ │ │ └── ScreenshotTest.java │ │ └── review │ │ │ ├── ChangeSetTestUtils.java │ │ │ ├── ReviewResultTest.java │ │ │ ├── ScreenshotChangesTest.java │ │ │ ├── SuiteChangeSetTest.java │ │ │ └── TestChangeSetTest.java │ └── util │ │ ├── ApprovalsUtil.java │ │ ├── ChecksumCalculatorTest.java │ │ ├── DeleteOnCloseFileInputStreamTest.java │ │ ├── FileUtilTest.java │ │ ├── ObjectUtilTest.java │ │ ├── OptionalUtilTest.java │ │ ├── ReflectionUtilitiesTest.java │ │ ├── RetestIdProviderUtilTest.java │ │ ├── RetestIdUtilTest.java │ │ ├── StackTraceParserTest.java │ │ ├── StringSimilarityTest.java │ │ ├── VersionProviderTest.java │ │ └── junit │ │ └── vintage │ │ └── LocaleRule.java │ ├── suite │ └── flow │ │ ├── ApplyChangesToStatesFlowTest.java │ │ └── CreateChangesetForAllDiffrencesFlowTest.java │ └── util │ └── XsdRegressionTest.java └── resources ├── ImageUtilsTest.png ├── ImageUtilsTestResize.png ├── de └── retest │ ├── image │ ├── PageRenderer_1.png │ ├── PageRenderer_2.png │ ├── PageRenderer_diff.png │ ├── fuzzy-diff-img1.png │ ├── fuzzy-diff-img2.png │ ├── fuzzy-diff-img_diff.png │ ├── img1.png │ ├── img2.png │ ├── img_diff_exact.png │ ├── img_diff_fuzzy.png │ ├── natural1.png │ ├── natural1_small.png │ ├── natural2.png │ ├── natural_diff.png │ ├── natural_small_diff.png │ ├── painted1.png │ ├── painted2.png │ └── painted_diff.png │ ├── recheck │ ├── RecheckCapMessageTest.no_golden_master_message_should_be_formatted_properly.approved.txt │ ├── RecheckImplIT.diff_should_be_created_accordingly.approved.txt │ ├── RecheckImplIT.diff_should_be_created_if_filtered.approved.txt │ ├── RecheckImplIT.diff_should_be_created_with_deleted_filtered.approved.txt │ ├── RecheckImplIT.diff_should_handle_legacy_spaces_accordingly.approved.txt │ ├── RecheckImplIT.diff_should_handle_spaces_accordingly.approved.txt │ ├── RecheckImplIT.diff_should_ignore_everything_but_include_deleted_and_same_attributes_with_change_suffix.approved.txt │ ├── elementcollection │ │ └── ElementCollectionPersistenceTest.check_persisted_xml.approved.xml │ ├── ignore │ │ ├── file.filter │ │ └── file.filter.js │ ├── persistence │ │ ├── bin │ │ │ ├── 1.6.0.report │ │ │ └── old.report │ │ ├── migration │ │ │ ├── RemoveElementTransformerIT.extended_xml_should_be_removed_correctly.approved.xml │ │ │ ├── RemoveElementTransformerIT.simple_xml_element_should_be_removed.approved.xml │ │ │ ├── XmlMigratorIT.loading_recheck_state_from_v3_1_0_should_work.approved.xml │ │ │ └── transformers │ │ │ │ ├── AddRetestIdTestTransformerIT.retestId_should_be_added.approved.xml │ │ │ │ ├── Path2XPathTransformerIT.path_should_be_transformed.approved.xml │ │ │ │ ├── PathAndType2LowerCaseTransformerIT.path_should_be_transformed.approved.xml │ │ │ │ └── WindowSuffixTransformerIT.transform_should_replace_window_with_suffixed_window.approved.xml │ │ └── xml │ │ │ ├── AttributesAdapterTest.inheriting_attributes_should_be_persistable.approved.xml │ │ │ ├── XmlFolderPersistenceTest.simple_save_to_folder.approved.xml │ │ │ ├── XmlTransformerTest.test.state0.xml │ │ │ ├── XmlTransformerTest.test.state1.xml │ │ │ └── XmlZipPersistenceTest.simple_save_to_file.approved.xml │ ├── printer │ │ └── ActionReplayResultPrinterTest.toString_should_not_print_child_differences_if_insertion_or_deletion.approved.txt │ ├── review │ │ └── workers │ │ │ ├── legacy-recheck.ignore │ │ │ └── recheck.ignore │ └── ui │ │ └── diff │ │ ├── AttributesDifferenceFinderTest.attributesDifference_with_different_key_and_different_values.approved.xml │ │ ├── AttributesDifferenceFinderTest.attributesDifference_with_less_expected_than_actual.approved.xml │ │ ├── AttributesDifferenceFinderTest.attributesDifference_with_more_expected_than_actual.approved.xml │ │ ├── AttributesDifferenceFinderTest.attributesDifference_with_the_same_key_but_different_values.approved.xml │ │ ├── IdentifyingAttributesDifferenceFinderTest.differences_should_be_recognized_accordingly.approved.xml │ │ ├── IdentifyingAttributesDifferenceFinderTest.different_paths_and_components_should_be_recognized_accordingly.approved.xml │ │ ├── RootElementDifferenceFinderTest.actual_root_element_is_null.approved.txt │ │ ├── RootElementDifferenceFinderTest.different_root_element_with_same_components_should_match.approved.txt │ │ ├── RootElementDifferenceFinderTest.expected_and_actual_root_element_are_different.approved.txt │ │ ├── RootElementDifferenceFinderTest.expected_root_element_is_null.approved.txt │ │ ├── RootElementDifferenceFinderTest.lists_of_different_root_element_are_matched_even_if_the_order_is_different.approved.txt │ │ ├── RootElementDifferenceFinderTest.lists_of_root_element_with_different_window_titles_are_matched.approved.txt │ │ └── RootElementDifferenceFinderTest.lists_of_root_element_with_different_window_titles_are_not_matched.approved.txt │ └── util │ └── XsdRegressionTest.checkXsd │ ├── ActionParameter.approved.xsd │ ├── ActionSequence.approved.xsd │ ├── Attribute.approved.xsd │ ├── AttributeDifference.approved.xsd │ ├── AttributesDifference.approved.xsd │ ├── CapturedSuite.approved.xsd │ ├── CodeLocAttribute.approved.xsd │ ├── ContextAttribute.approved.xsd │ ├── DefaultAttribute.approved.xsd │ ├── ElementCollection.approved.xsd │ ├── ElementDifference.approved.xsd │ ├── ExecutableSuite.approved.xsd │ ├── IdentifyingAttributesDifference.approved.xsd │ ├── InsertedDeletedElementDifference.approved.xsd │ ├── OutlineAttribute.approved.xsd │ ├── ParameterizedAction.approved.xsd │ ├── PathAttribute.approved.xsd │ ├── ReTestXmlDataContainer.approved.xsd │ ├── RootElementDifference.approved.xsd │ ├── ScreenshotAttributeDifference.approved.xsd │ ├── StateDifference.approved.xsd │ ├── StringAttribute.approved.xsd │ ├── SuffixAttribute.approved.xsd │ ├── Test.approved.xsd │ ├── TextAttribute.approved.xsd │ └── WeightedTextAttribute.approved.xsd ├── migration ├── AddRetestIdTestTransformer.xml ├── Path2XPathTransformer.xml ├── PathAndType2LowerCaseTransformer.xml ├── WindowSuffixTransformerTest.xml ├── XmlMigratorTest-retest-v3.1.0.xml ├── XmlMigratorTest-v1.xml └── XmlMigratorTest-v2.xml ├── persistence ├── empty.zip ├── simple_folder_persisted │ └── retest.xml └── simple_zip_persisted.zip ├── recheck └── ApplyChangesToStatesFlowTest │ └── check_GUI_with_review_license.launch.recheck └── retest └── recheck ├── de.retest.recheck.RecheckImplIT legacy spaces └── with legacy spaces.check.recheck │ └── retest.xml ├── de.retest.recheck.RecheckImplIT spaces └── with spaces.check.recheck │ └── retest.xml └── de.retest.recheck.RecheckImplIT ├── filter-deleted.check.recheck └── retest.xml ├── filter.check.recheck └── retest.xml ├── no-filter.check.recheck └── retest.xml └── with_exclude.check.recheck └── retest.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css text encoding=utf-8 eol=lf 2 | *.html text encoding=utf-8 eol=lf 3 | *.ignore text encoding=utf-8 eol=lf 4 | *.java text encoding=utf-8 eol=lf 5 | *.js text encoding=utf-8 eol=lf 6 | *.md text encoding=utf-8 eol=lf 7 | *.properties text encoding=utf-8 eol=lf 8 | *.sh text encoding=utf-8 eol=lf 9 | *.xml text encoding=utf-8 eol=lf 10 | *.yaml text encoding=utf-8 eol=lf 11 | *.yml text encoding=utf-8 eol=lf 12 | *.cmd text encoding=utf-8 eol=crlf 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature 3 | about: Create a issue that suggests or improves a feature 4 | labels: enhancement 5 | --- 6 | 7 | *Before submission, please check that ...* 8 | 9 | - [ ] this is related specifically to recheck and not its extension (e.g. [recheck-web](https://github.com/retest/recheck-web)). 10 | - [ ] the [documentation](https://docs.retest.de/) does not mention a similar solution (e.g. possible configurations). 11 | - [ ] there are no open or closed issues that are related to this idea. 12 | - [ ] this, to my best knowledge, will not break something else. 13 | 14 | 15 | 16 | ## Problem 17 | 18 | 19 | 20 | ### Solution 21 | 22 | 23 | 24 | ### Additional Context 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | timezone: Europe/Berlin 9 | open-pull-requests-limit: 10 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | *Before submission, please check that ...* 2 | 3 | - [ ] the code follows the [Clean Code](https://clean-code-developer.com/) guidelines. 4 | - [ ] the necessary tests are either created or updated. 5 | - [ ] all status checks (Travis CI, SonarCloud, etc.) pass. 6 | - [ ] your commit history is cleaned up. 7 | - [ ] you updated the changelog. 8 | - [ ] you updated necessary documentation within [retest/docs](https://github.com/retest/docs). 9 | 10 | 11 | 12 | ## Description 13 | 14 | > TL;DR 15 | 16 | 17 | 18 | ### State of this PR 19 | 20 | 21 | 22 | ### Additional Context 23 | 24 | -------------------------------------------------------------------------------- /.github/workflows/deploy-release.yml: -------------------------------------------------------------------------------- 1 | name: Deploy releases 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | env: 9 | MVN_ARGS: --batch-mode --errors --fail-fast --no-transfer-progress 10 | 11 | jobs: 12 | default: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - uses: actions/setup-java@v1 20 | with: 21 | java-version: 8 22 | server-id: ossrh 23 | server-username: MAVEN_USERNAME 24 | server-password: MAVEN_PASSWORD 25 | 26 | - name: Cache local Maven repository 27 | uses: actions/cache@v2 28 | with: 29 | path: ~/.m2/repository 30 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 31 | restore-keys: ${{ runner.os }}-maven- 32 | 33 | - name: Install gpg secret key 34 | run: | 35 | gpg --batch --import <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") 36 | gpg --list-secret-keys --keyid-format LONG 37 | 38 | - id: publish-to-central 39 | name: Publish to Central Repository 40 | run: | 41 | mvn ${MVN_ARGS} -DskipTests -Psign clean deploy 42 | env: 43 | GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_PASSPHRASE }} 44 | MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} 45 | MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} 46 | -------------------------------------------------------------------------------- /.github/workflows/release-feature-finish.yml: -------------------------------------------------------------------------------- 1 | name: Release feature finish 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | approval: 7 | description: 'Do you really want to finish the current FEATURE release?' 8 | required: true 9 | default: 'NO' 10 | 11 | env: 12 | MVN_ARGS: --batch-mode --errors --fail-fast --no-transfer-progress 13 | 14 | jobs: 15 | default: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Verify approval 21 | run: "[[ $(echo ${{ github.event.inputs.approval }} | tr 'a-z' 'A-Z') == 'YES' ]]" 22 | 23 | - uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 0 26 | token: ${{ secrets.TRIGGER_ACTIONS_GITHUB_TOKEN }} 27 | 28 | - uses: actions/setup-java@v1 29 | with: 30 | java-version: 8 31 | 32 | - name: Cache local Maven repository 33 | uses: actions/cache@v2 34 | with: 35 | path: ~/.m2/repository 36 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 37 | restore-keys: ${{ runner.os }}-maven- 38 | 39 | - name: Configure Git user 40 | run: | 41 | git config user.email "ops+githubactions@retest.de" 42 | git config user.name "retest release github action" 43 | 44 | - name: Tag and finish release branch 45 | run: mvn ${MVN_ARGS} gitflow:release-finish 46 | -------------------------------------------------------------------------------- /.github/workflows/release-feature-start.yml: -------------------------------------------------------------------------------- 1 | name: Release feature start 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | approval: 7 | description: 'Do you really want to start a FEATURE release from DEVELOP branch?' 8 | required: true 9 | default: 'NO' 10 | 11 | env: 12 | MVN_ARGS: --batch-mode --errors --fail-fast --no-transfer-progress 13 | 14 | jobs: 15 | default: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Verify approval 21 | run: "[[ $(echo ${{ github.event.inputs.approval }} | tr 'a-z' 'A-Z') == 'YES' ]]" 22 | 23 | - uses: actions/checkout@v2 24 | with: 25 | token: ${{ secrets.TRIGGER_ACTIONS_GITHUB_TOKEN }} 26 | 27 | - uses: actions/setup-java@v1 28 | with: 29 | java-version: 8 30 | 31 | - name: Cache local Maven repository 32 | uses: actions/cache@v2 33 | with: 34 | path: ~/.m2/repository 35 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 36 | restore-keys: ${{ runner.os }}-maven- 37 | 38 | - name: Configure Git user 39 | run: | 40 | git config user.email "ops+githubactions@retest.de" 41 | git config user.name "retest release github action" 42 | 43 | 44 | - name: Start release branch 45 | run: mvn ${MVN_ARGS} gitflow:release-start 46 | -------------------------------------------------------------------------------- /.github/workflows/release-hotfix-finish.yml: -------------------------------------------------------------------------------- 1 | name: Release hotfix finish 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | approval: 7 | description: 'Do you really want to finish the current HOTFIX release?' 8 | required: true 9 | default: 'NO' 10 | 11 | env: 12 | MVN_ARGS: --batch-mode --errors --fail-fast --no-transfer-progress 13 | 14 | jobs: 15 | default: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Verify approval 21 | run: "[[ $(echo ${{ github.event.inputs.approval }} | tr 'a-z' 'A-Z') == 'YES' ]]" 22 | 23 | - uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 0 26 | token: ${{ secrets.TRIGGER_ACTIONS_GITHUB_TOKEN }} 27 | 28 | - uses: actions/setup-java@v1 29 | with: 30 | java-version: 8 31 | 32 | - name: Cache local Maven repository 33 | uses: actions/cache@v2 34 | with: 35 | path: ~/.m2/repository 36 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 37 | restore-keys: ${{ runner.os }}-maven- 38 | 39 | - name: Configure Git user 40 | run: | 41 | git config user.email "ops+githubactions@retest.de" 42 | git config user.name "retest release github action" 43 | 44 | - name: Tag and finish release branch 45 | run: mvn ${MVN_ARGS} gitflow:hotfix-finish 46 | -------------------------------------------------------------------------------- /.github/workflows/release-hotfix-start.yml: -------------------------------------------------------------------------------- 1 | name: Release hotfix start 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | approval: 7 | description: 'Do you really want to start a HOTFIX release from MAIN branch?' 8 | required: true 9 | default: 'NO' 10 | 11 | env: 12 | MVN_ARGS: --batch-mode --errors --fail-fast --no-transfer-progress 13 | 14 | jobs: 15 | default: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Verify approval 21 | run: "[[ $(echo ${{ github.event.inputs.approval }} | tr 'a-z' 'A-Z') == 'YES' ]]" 22 | 23 | - uses: actions/checkout@v2 24 | with: 25 | token: ${{ secrets.TRIGGER_ACTIONS_GITHUB_TOKEN }} 26 | 27 | - uses: actions/setup-java@v1 28 | with: 29 | java-version: 8 30 | 31 | - name: Cache local Maven repository 32 | uses: actions/cache@v2 33 | with: 34 | path: ~/.m2/repository 35 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 36 | restore-keys: ${{ runner.os }}-maven- 37 | 38 | - name: Configure Git user 39 | run: | 40 | git config user.email "ops+githubactions@retest.de" 41 | git config user.name "retest release github action" 42 | 43 | 44 | - name: Start release branch 45 | run: mvn ${MVN_ARGS} gitflow:hotfix-start 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse. 2 | .classpath 3 | .project 4 | .settings/ 5 | 6 | # IntelliJ. 7 | .idea/ 8 | *.iml 9 | 10 | # Maven. 11 | /target/ 12 | 13 | -------------------------------------------------------------------------------- /.retest/recheck.ignore: -------------------------------------------------------------------------------- 1 | # Ignore file for recheck. Please do not delete, even if it is empty. 2 | 3 | # You can ignore specific elements like so (includes children): 4 | # matcher: type=meta 5 | 6 | # Or via absolute XPath: 7 | # matcher: xpath=html[1]/body[1]/iframe[1] 8 | 9 | # Or if you want to ignore everything, except specific dom-subtrees: 10 | # matcher: type=html, exclude(matcher: xpath=html/body/section[4]) 11 | 12 | # To ignore attributes globally, use: 13 | # attribute=class 14 | 15 | # To ignore attributes for a subtree of the DOM, use: 16 | # matcher: id=menu, attribute=text 17 | 18 | # You can also use regex for elements or attributes: 19 | # attribute-regex=data-.* 20 | 21 | # You can import other filters to quickly achieve what you want: 22 | # import: positioning.filter 23 | 24 | # More details and examples can be found here: 25 | # https://docs.retest.de/recheck/usage/filter/ 26 | 27 | # Ignore volatile metadata differences 28 | import: volatile-metadata.filter 29 | 30 | # These are sensible defaults, delete if they don't apply: 31 | attribute=style 32 | matcher: type=input, attribute-regex=border-.*-color 33 | pixel-diff=5px 34 | -------------------------------------------------------------------------------- /.retest/recheck.ignore.js: -------------------------------------------------------------------------------- 1 | // Here you can implement ignore rules for recheck in JavaScript. 2 | // Please do not delete this file, even if it is empty. 3 | 4 | // You can implement either of these two functions: 5 | // function matches(element) {} 6 | // function matches(element, diff) {} 7 | 8 | // For example, to ignore everything behind an URL after '?': 9 | 10 | //var baseUrl = /http[s]?:\/\/[\w.:\d\-]*/; 11 | // 12 | //function matches(element, diff) { 13 | // if (diff.expected != null && diff.actual != null) { 14 | // expected = new String(diff.expected); 15 | // actual = new String(diff.actual); 16 | // cleanExpected = expected.replace(baseUrl, ''); 17 | // cleanActual = actual.replace(baseUrl, ''); 18 | // return cleanExpected === cleanActual; 19 | // } 20 | // return false; 21 | //} 22 | 23 | // You can find more details and example rules at: 24 | // https://docs.retest.de/recheck/how-ignore-works/ 25 | -------------------------------------------------------------------------------- /.retest/recheck.js.ignore: -------------------------------------------------------------------------------- 1 | // Ignore for recheck. Please do not delete, even if they appear to be empty 2 | -------------------------------------------------------------------------------- /.retest/retest.properties: -------------------------------------------------------------------------------- 1 | # Defaults for recheck. Please do not delete, even if this file is empty. 2 | 3 | # Upload test reports to rehub. 4 | # de.retest.recheck.rehub.reportUploadEnabled=false 5 | 6 | # Always ignore these (separate values with ;) attributes. 7 | de.retest.recheck.ignore.attributes=absolute-outline 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | The ***retest*** Code of Conduct can be found at https://docs.retest.de/code-of-conduct. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | The ***retest*** Contributing Guidelines can be found at https://docs.retest.de/contributing. 4 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ExecutingTestContext.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck; 2 | 3 | import java.util.Set; 4 | 5 | import de.retest.recheck.persistence.Persistable; 6 | import de.retest.recheck.persistence.Persistence; 7 | import de.retest.recheck.ui.Environment; 8 | import de.retest.recheck.ui.IgnoredTypes; 9 | import de.retest.recheck.ui.descriptors.GroundState; 10 | 11 | public interface ExecutingTestContext { 12 | 13 | @SuppressWarnings( "rawtypes" ) 14 | Environment getEnvironment(); 15 | 16 | Set> getXmlDataClasses(); 17 | 18 | GroundState createGroundState(); 19 | 20 | Persistence getPersistence(); 21 | 22 | IgnoredTypes getIgnoredTypes(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/RecheckLifecycle.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck; 2 | 3 | /** 4 | * Interface defining the lifecycle functionality to write tests with recheck. 5 | * 6 | * @apiNote Provided {@link RecheckOptions} should be honored and fully supported. 7 | */ 8 | public interface RecheckLifecycle { 9 | 10 | /** 11 | * Start a test and infer the test name from the calling method. 12 | */ 13 | void startTest(); 14 | 15 | /** 16 | * Tells recheck that a test has started. This helps to check multiple states within a single test. 17 | * 18 | * @param testName 19 | * the name of the test 20 | */ 21 | void startTest( String testName ); 22 | 23 | /** 24 | * Tells recheck that the test has finished. If one or more checks during this tests resulted in differences, this 25 | * triggers an {@link AssertionError} to be thrown like any other assertion would. Still, the differences are 26 | * persisted as test reports into the target folder. 27 | */ 28 | void capTest() throws AssertionError; 29 | 30 | /** 31 | * Finishes recheck and persists the test report. Starting the review GUI is sensible. 32 | */ 33 | void cap(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/SutStateLoader.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck; 2 | 3 | import java.io.File; 4 | 5 | import de.retest.recheck.ui.descriptors.SutState; 6 | 7 | public interface SutStateLoader { 8 | 9 | SutState loadExpected( final File file ); 10 | 11 | SutState createNew( final File file, final SutState actual ); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/auth/AuthenticationHandler.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.auth; 2 | 3 | import java.net.URI; 4 | 5 | public interface AuthenticationHandler { 6 | 7 | void showWebLoginUri( URI loginUri ); 8 | 9 | void loginPerformed( String token ); 10 | 11 | void loginFailed( Throwable reason ); 12 | 13 | void logoutPerformed(); 14 | 15 | void logoutFailed( Throwable reason ); 16 | 17 | String getOfflineToken(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/auth/DefaultAuthenticationHandler.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.auth; 2 | 3 | import java.net.URI; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class DefaultAuthenticationHandler implements AuthenticationHandler { 9 | 10 | private static final Logger logger = LoggerFactory.getLogger( DefaultAuthenticationHandler.class ); 11 | 12 | @Override 13 | public void showWebLoginUri( final URI loginUri ) { 14 | logger.info( "Log in using '{}'.", loginUri ); 15 | } 16 | 17 | @Override 18 | public void loginPerformed( final String token ) { 19 | logger.info( "Login successful." ); 20 | } 21 | 22 | @Override 23 | public void loginFailed( final Throwable reason ) { 24 | logger.error( "Login failed: ", reason ); 25 | } 26 | 27 | @Override 28 | public String getOfflineToken() { 29 | return null; 30 | } 31 | 32 | @Override 33 | public void logoutPerformed() { 34 | logger.info( "Logout successful." ); 35 | } 36 | 37 | @Override 38 | public void logoutFailed( final Throwable reason ) { 39 | logger.error( "Logout failed:", reason ); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/auth/KeycloakResult.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.auth; 2 | 3 | import java.io.IOException; 4 | 5 | import lombok.Builder; 6 | import lombok.Data; 7 | 8 | @Data 9 | @Builder 10 | public class KeycloakResult { 11 | private final String code; 12 | private final String error; 13 | private final String errorDescription; 14 | private final IOException errorException; 15 | private final String state; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/auth/UnableToAuthenticateOfflineException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.auth; 2 | 3 | public class UnableToAuthenticateOfflineException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public UnableToAuthenticateOfflineException( final Throwable cause ) { 8 | super( "It appears you are offline. You need either to be online or have a special offline-license.", cause ); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/configuration/ProjectConfigurationUtil.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.configuration; 2 | 3 | import static de.retest.recheck.RecheckProperties.RETEST_FOLDER_NAME; 4 | 5 | import java.nio.file.Path; 6 | import java.util.Optional; 7 | 8 | public class ProjectConfigurationUtil { 9 | 10 | private ProjectConfigurationUtil() {} 11 | 12 | public static Optional findProjectConfigurationFolder() { 13 | return ProjectRootFinderUtil.getProjectRoot().map( path -> path.resolve( RETEST_FOLDER_NAME ) ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/configuration/ProjectRootFinder.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.configuration; 2 | 3 | import java.nio.file.Path; 4 | import java.util.Optional; 5 | 6 | public interface ProjectRootFinder { 7 | 8 | /** 9 | * Searches for a recheck project root folder, starting from the given {@code basePath} and moving up to the root of 10 | * the filesystem. This can be used to locate the project root for a given path to a report. 11 | * 12 | * @param basePath 13 | * the path to start the search from 14 | * @return an optional consisting of the project root path if it has been found, otherwise empty 15 | */ 16 | Optional findProjectRoot( Path basePath ); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/configuration/ProjectRootFinderUtil.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.configuration; 2 | 3 | import java.nio.file.Path; 4 | import java.nio.file.Paths; 5 | import java.util.Optional; 6 | import java.util.Set; 7 | 8 | import com.google.common.collect.Sets; 9 | 10 | import de.retest.recheck.util.OptionalUtil; 11 | 12 | public class ProjectRootFinderUtil { 13 | 14 | private static final Set projectRootFinder = Sets.newHashSet( new PathBasedProjectRootFinder() ); 15 | 16 | private ProjectRootFinderUtil() {} 17 | 18 | public static Optional getProjectRoot() { 19 | final Path baseFolder = Paths.get( System.getProperty( ProjectConfiguration.RETEST_PROJECT_ROOT, "" ) ); 20 | return getProjectRoot( baseFolder.toAbsolutePath() ); 21 | } 22 | 23 | public static Optional getProjectRoot( final Path basePath ) { 24 | return projectRootFinder.stream() // 25 | .map( finder -> finder.findProjectRoot( basePath ) ) // 26 | .flatMap( OptionalUtil::stream ) // 27 | .findAny(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/execution/RecheckAdapters.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.execution; 2 | 3 | import java.util.ServiceLoader; 4 | import java.util.stream.StreamSupport; 5 | 6 | import de.retest.recheck.RecheckAdapter; 7 | import de.retest.recheck.RecheckOptions; 8 | 9 | public class RecheckAdapters { 10 | 11 | private static final ServiceLoader adapters = ServiceLoader.load( RecheckAdapter.class ); 12 | 13 | private RecheckAdapters() {} 14 | 15 | public static RecheckAdapter findAdapterFor( final Object toVerify, final RecheckOptions options ) { 16 | return StreamSupport.stream( adapters.spliterator(), false ) // 17 | .filter( adapter -> adapter.canCheck( toVerify ) ) // 18 | .findAny() // 19 | .orElseThrow( () -> createHelpfulExceptionForMissingAdapter( toVerify.getClass().getName() ) ) 20 | .initialize( options ); 21 | } 22 | 23 | static UnsupportedOperationException createHelpfulExceptionForMissingAdapter( final String className ) { 24 | final String msg = 25 | String.format( "No recheck adapter registered that can handle an object of class %s.", className ); 26 | if ( className.startsWith( "org.openqa.selenium" ) ) { 27 | return new UnsupportedOperationException( 28 | msg + "\n You need to add recheck-web (https://github.com/retest/recheck-web) to the classpath." ); 29 | } 30 | return new UnsupportedOperationException( msg ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ignore/FilterAllAttributes.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import de.retest.recheck.ui.descriptors.Element; 4 | import de.retest.recheck.ui.diff.AttributeDifference; 5 | 6 | public class FilterAllAttributes implements Filter { 7 | 8 | @Override 9 | public boolean matches( final Element element ) { 10 | return false; 11 | } 12 | 13 | @Override 14 | public boolean matches( final Element element, final AttributeDifference attributeDifference ) { 15 | return true; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ignore/FilterLoader.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import static de.retest.recheck.ignore.SearchFilterFiles.FILTER_JS_EXTENSION; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.nio.charset.StandardCharsets; 8 | import java.nio.file.NoSuchFileException; 9 | import java.nio.file.Path; 10 | import java.nio.file.Paths; 11 | 12 | import org.apache.commons.io.IOUtils; 13 | 14 | public interface FilterLoader { 15 | 16 | Filter load() throws IOException; 17 | 18 | static FilterLoader loadResource( final String path ) { 19 | return () -> { 20 | try ( final InputStream stream = FilterLoader.class.getResourceAsStream( path ) ) { 21 | if ( stream == null ) { 22 | throw new NoSuchFileException( path ); 23 | } 24 | return Filters.parse( Paths.get( path ), IOUtils.readLines( stream, StandardCharsets.UTF_8 ).stream() ); 25 | } 26 | }; 27 | } 28 | 29 | static FilterLoader load( final Path path ) { 30 | if ( path.toString().toLowerCase().endsWith( FILTER_JS_EXTENSION ) ) { 31 | return () -> new JSFilterImpl( path ); 32 | } 33 | return () -> Filters.load( path ); 34 | } 35 | 36 | static FilterLoader provide( final Path path ) throws IOException { 37 | final Filter filter = Filters.load( path ); 38 | return () -> filter; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ignore/FilterNotFoundException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import java.util.Optional; 4 | 5 | import lombok.Getter; 6 | 7 | @Getter 8 | public class FilterNotFoundException extends RuntimeException { 9 | 10 | private static final long serialVersionUID = 2L; 11 | 12 | private final String filterName; 13 | private final String projectFilterDir; 14 | 15 | public FilterNotFoundException( final String filterName ) { 16 | super( "No filter with name '" + filterName 17 | + "' found in the user home and among the predefined default filters. (No project to search in available.)" ); 18 | this.filterName = filterName; 19 | projectFilterDir = null; 20 | } 21 | 22 | public FilterNotFoundException( final String filterName, final String projectFilterDir ) { 23 | super( "No filter with name '" + filterName + "' found in the project filter folder '" + projectFilterDir 24 | + "', the user home and among the predefined default filters." ); 25 | this.filterName = filterName; 26 | this.projectFilterDir = projectFilterDir; 27 | } 28 | 29 | public Optional getProjectFilterDir() { 30 | return Optional.ofNullable( projectFilterDir ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ignore/FilterOutline.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import de.retest.recheck.ui.descriptors.Element; 4 | import de.retest.recheck.ui.descriptors.OutlineAttribute; 5 | 6 | public class FilterOutline implements Filter { 7 | 8 | @Override 9 | public boolean matches( final Element element ) { 10 | return false; 11 | } 12 | 13 | @Override 14 | public boolean matches( final Element element, final String attributeKey ) { 15 | return OutlineAttribute.RELATIVE_OUTLINE.equalsIgnoreCase( attributeKey ) 16 | || OutlineAttribute.ABSOLUTE_OUTLINE.equalsIgnoreCase( attributeKey ); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ignore/Filters.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import static de.retest.recheck.ignore.PersistentFilter.wrap; 4 | 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | import java.util.stream.Stream; 11 | 12 | import de.retest.recheck.review.ignore.io.Loaders; 13 | 14 | public class Filters { 15 | 16 | private Filters() {} 17 | 18 | public static Filter load( final Path path ) throws IOException { 19 | try ( final Stream filterFileLines = Files.lines( path ) ) { 20 | return parse( path, filterFileLines ); 21 | } 22 | } 23 | 24 | public static Filter parse( final String line ) { 25 | return parse( Stream.of( line ) ); 26 | } 27 | 28 | public static Filter parse( final List lines ) { 29 | return parse( lines.stream() ); 30 | } 31 | 32 | public static Filter parse( final Stream lines ) { 33 | return new CompoundFilter( Loaders.filter().load( lines ).collect( Collectors.toList() ) ); 34 | } 35 | 36 | public static Filter parse( final Path path, final Stream lines ) { 37 | return new CompoundFilter( wrap( path, Loaders.filter().load( lines ) ).collect( Collectors.toList() ) ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/image/ImageDiffCalcFactory.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.image; 2 | 3 | public class ImageDiffCalcFactory { 4 | 5 | private ImageDiffCalcFactory() {} 6 | 7 | private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger( ImageDiffCalcFactory.class ); 8 | 9 | private static final String IMAGE_DIFFERENCE_CALCULATOR = "de.retest.image.DifferenceCalculator"; 10 | 11 | public static ImageDifferenceCalculator getConfiguredImageDifferenceCalculator() { 12 | final String configured = System.getProperty( IMAGE_DIFFERENCE_CALCULATOR ); 13 | if ( configured != null ) { 14 | try { 15 | logger.info( "Using '{}' as ImageDifferenceCalculator.", configured ); 16 | return (ImageDifferenceCalculator) Class.forName( configured ).newInstance(); 17 | } catch ( final Exception exc ) { 18 | logger.error( "Error creating configured ImageDifferenceCalculator {}:", configured, exc ); 19 | } 20 | } 21 | logger.info( "No ImageDifferenceCalculator specified, will use default." ); 22 | return new ExactImageDifferenceCalculator(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/image/ImageDifference.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.image; 2 | 3 | import java.awt.image.BufferedImage; 4 | 5 | public class ImageDifference { 6 | // to make sure to account for rounding errors 7 | private static final double EQUALITY_THRESHOLD = 0.9999999999; 8 | 9 | private final BufferedImage differenceImage; 10 | private final double match; 11 | private final String strategyName; 12 | 13 | public ImageDifference( final double match, final BufferedImage differenceImage, final Class strategy ) { 14 | this.match = match; 15 | this.differenceImage = differenceImage; 16 | strategyName = strategy.getName(); 17 | } 18 | 19 | public BufferedImage getDifferenceImage() { 20 | return differenceImage; 21 | } 22 | 23 | public double getMatch() { 24 | return match; 25 | } 26 | 27 | public boolean isEqual() { 28 | return match > EQUALITY_THRESHOLD; 29 | } 30 | 31 | public String getStrategyName() { 32 | return strategyName; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/image/ImageDifferenceCalculator.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.image; 2 | 3 | import java.awt.image.BufferedImage; 4 | 5 | import de.retest.recheck.ui.image.Screenshot; 6 | 7 | public interface ImageDifferenceCalculator { 8 | 9 | ImageDifference compare( BufferedImage img1, BufferedImage img2 ); 10 | 11 | ImageDifference compare( Screenshot expected, Screenshot actual ); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ioerror/ReTestIOException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ioerror; 2 | 3 | import java.io.IOException; 4 | import java.net.URI; 5 | 6 | public class ReTestIOException extends IOException { 7 | 8 | private static final long serialVersionUID = 1L; 9 | private final URI location; 10 | 11 | public ReTestIOException( final URI location, final Throwable throwable ) { 12 | this( location, throwable.getMessage(), throwable ); 13 | } 14 | 15 | public ReTestIOException( final URI location, final String details ) { 16 | super( "Error reading from '" + location + "': " + details ); 17 | this.location = location; 18 | } 19 | 20 | public ReTestIOException( final URI location, final String details, final Throwable throwable ) { 21 | super( "Error reading from '" + location + "': " + details, throwable ); 22 | this.location = location; 23 | } 24 | 25 | public URI getLocation() { 26 | return location; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ioerror/ReTestLoadException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ioerror; 2 | 3 | import java.net.URI; 4 | 5 | public class ReTestLoadException extends ReTestIOException { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | public ReTestLoadException( final URI location, final Throwable throwable ) { 10 | super( location, throwable ); 11 | } 12 | 13 | public ReTestLoadException( final URI location, final String details ) { 14 | super( location, details ); 15 | } 16 | 17 | public ReTestLoadException( final URI location, final String details, final Throwable throwable ) { 18 | super( location, details, throwable ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ioerror/ReTestSaveException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ioerror; 2 | 3 | import java.net.URI; 4 | 5 | public class ReTestSaveException extends ReTestIOException { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | public ReTestSaveException( final URI location, final Throwable throwable ) { 10 | super( location, throwable ); 11 | } 12 | 13 | public ReTestSaveException( final URI location, final String details, final Throwable throwable ) { 14 | super( location, details, throwable ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/meta/GlobalMetadataProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta; 2 | 3 | import java.util.Map; 4 | 5 | import de.retest.recheck.meta.global.GitMetadataProvider; 6 | import de.retest.recheck.meta.global.MachineMetadataProvider; 7 | import de.retest.recheck.meta.global.OSMetadataProvider; 8 | import de.retest.recheck.meta.global.TimeMetadataProvider; 9 | 10 | /** 11 | * Provides generic metadata that apply in particular to the current context in which a program is executed. This 12 | * includes for example: 13 | *
    14 | *
  • The operating systems name and version.
  • 15 | *
  • The date and time executed.
  • 16 | *
  • ...
  • 17 | *
18 | */ 19 | final class GlobalMetadataProvider implements MetadataProvider { 20 | 21 | private final MetadataProvider globalProvider = MultiMetadataProvider.of( // 22 | new GitMetadataProvider(), // 23 | new MachineMetadataProvider(), // 24 | new OSMetadataProvider(), // 25 | new TimeMetadataProvider() // 26 | ); 27 | 28 | @Override 29 | public Map retrieve() { 30 | return globalProvider.retrieve(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/meta/MultiMetadataProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.stream.Collectors; 8 | 9 | import lombok.AccessLevel; 10 | import lombok.RequiredArgsConstructor; 11 | 12 | /** 13 | * Combines multiple {@link MetadataProvider} together into a single metadata. This may be used to combine multiple 14 | * smaller, specified providers together or simply collect a list of unrelated providers. 15 | * 16 | * Key collisions will be resolved with the last value encountered. 17 | */ 18 | @RequiredArgsConstructor( access = AccessLevel.PRIVATE ) 19 | public final class MultiMetadataProvider implements MetadataProvider { 20 | 21 | private final List providers; 22 | 23 | public static MetadataProvider of( final MetadataProvider... providers ) { 24 | return of( Arrays.asList( providers ) ); 25 | } 26 | 27 | public static MetadataProvider of( final List providers ) { 28 | return new MultiMetadataProvider( providers ); 29 | } 30 | 31 | @Override 32 | public Map retrieve() { 33 | return providers.stream() // 34 | .map( MetadataProvider::retrieve ) // 35 | .map( Map::entrySet ) // 36 | .flatMap( Set::stream ) // 37 | .collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, ( left, right ) -> right ) ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/meta/global/GitMetadataProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta.global; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import de.retest.recheck.meta.MetadataProvider; 7 | import de.retest.recheck.persistence.GitExecutor; 8 | 9 | public final class GitMetadataProvider implements MetadataProvider { 10 | 11 | public static final String VCS_GIT = "git"; 12 | public static final String VCS_NAME = "vcs.name"; 13 | public static final String BRANCH_NAME = "vcs.branch"; 14 | public static final String COMMIT_NAME = "vcs.commit"; 15 | 16 | private final GitExecutor git; 17 | 18 | public GitMetadataProvider() { 19 | this( new GitExecutor() ); 20 | } 21 | 22 | protected GitMetadataProvider( final GitExecutor git ) { 23 | this.git = git; 24 | } 25 | 26 | @Override 27 | public Map retrieve() { 28 | final Map map = new HashMap<>(); 29 | 30 | final String branch = git.getCurrentBranch(); 31 | final String commit = git.getCurrentCommit(); 32 | if ( branch != null && commit != null ) { 33 | map.put( VCS_NAME, VCS_GIT ); 34 | map.put( BRANCH_NAME, branch ); 35 | map.put( COMMIT_NAME, commit ); 36 | } 37 | 38 | return map; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/meta/global/MachineMetadataProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta.global; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.apache.commons.lang3.SystemUtils; 7 | 8 | import de.retest.recheck.meta.MetadataProvider; 9 | 10 | public final class MachineMetadataProvider implements MetadataProvider { 11 | 12 | public static final String MACHINE_NAME = "machine.name"; 13 | 14 | @Override 15 | public Map retrieve() { 16 | final Map map = new HashMap<>(); 17 | 18 | final String hostName = SystemUtils.getHostName(); 19 | if ( hostName != null ) { 20 | map.put( MACHINE_NAME, hostName ); 21 | } 22 | 23 | return map; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/meta/global/OSMetadataProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta.global; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.apache.commons.lang3.SystemUtils; 7 | 8 | import de.retest.recheck.meta.MetadataProvider; 9 | 10 | public final class OSMetadataProvider implements MetadataProvider { 11 | 12 | public static final String OS_ARCH = "os.arch"; 13 | public static final String OS_NAME = "os.name"; 14 | public static final String OS_VERSION = "os.version"; 15 | 16 | @Override 17 | public Map retrieve() { 18 | final Map map = new HashMap<>(); 19 | // These are required java system properties, thus they should always be set 20 | map.put( OS_ARCH, SystemUtils.OS_ARCH ); 21 | map.put( OS_NAME, SystemUtils.OS_NAME ); 22 | map.put( OS_VERSION, SystemUtils.OS_VERSION ); 23 | return map; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/ClassAndMethodBasedNamingStrategy.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import de.retest.recheck.TestCaseFinder; 4 | 5 | /** 6 | * The default implementation that derives test suite and test case name from the test class and test method, working 7 | * for both JUnit and TestNG. 8 | */ 9 | public class ClassAndMethodBasedNamingStrategy implements NamingStrategy { 10 | 11 | @Override 12 | public String getSuiteName() { 13 | return TestCaseFinder.getInstance() // 14 | .findTestCaseClassNameInStack() // 15 | .orElseThrow( () -> new IllegalStateException( "Couldn't identify test class in call stack.\n" 16 | + "This is needed to dynamically name the Golden Master files.\n " 17 | + "Please call `suiteName(\"name\")` in RecheckImpl with RecheckOptions, giving an explicit name, " 18 | + "or instantiate it in a method, and provide a different NamingStrategy." ) ); 19 | } 20 | 21 | @Override 22 | public String getTestName() { 23 | return TestCaseFinder.getInstance() // 24 | .findTestCaseMethodNameInStack() // 25 | .orElseThrow( () -> new IllegalStateException( "Couldn't identify test method in call stack.\n" 26 | + "This is needed to dynamically name the Golden Master files.\n" 27 | + "Please call `startTest(\"name\")`, giving an explicit name, " 28 | + "or instantiate RecheckImpl with RecheckOptions, and provide a different NamingStrategy." ) ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/ClassAndMethodBasedShortNamingStrategy.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | /** 4 | * Extends the standard {@link ClassAndMethodBasedNamingStrategy}, but instead of the qualified class name (e.g. 5 | * `com.mycompany.MyTest`) returns the {@link Class#getSimpleName()} of the class (e.g. `MyTest`). 6 | */ 7 | public class ClassAndMethodBasedShortNamingStrategy extends ClassAndMethodBasedNamingStrategy { 8 | 9 | /** 10 | * @return The {@link Class#getSimpleName()} of the test class (e.g. `MyTest`). 11 | */ 12 | @Override 13 | public String getSuiteName() { 14 | String result = super.getSuiteName(); 15 | if ( result.contains( "." ) ) { 16 | result = result.substring( result.lastIndexOf( '.' ) + 1 ); 17 | } 18 | if ( result.contains( "$" ) ) { 19 | result = result.substring( 0, result.indexOf( '$' ) ); 20 | } 21 | return result; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/ExplicitMutableNamingStrategy.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * A naming strategy without magic, where the values of suiteName and testName can be changed at will. Please note that 7 | * the caller must ensure thread safety when executing tests in parallel. 8 | */ 9 | @Data 10 | public class ExplicitMutableNamingStrategy implements NamingStrategy { 11 | 12 | private String suiteName; 13 | private String testName; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/FileNamer.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * @deprecated Use {@link ProjectLayout} instead. 7 | */ 8 | @Deprecated 9 | public interface FileNamer { 10 | 11 | /** 12 | * @param extension 13 | * The file extension to be used. 14 | * @return The Golden Master file. 15 | */ 16 | File getFile( String extension ); 17 | 18 | /** 19 | * @param extension 20 | * The file extension to be used. 21 | * @return The test report file. 22 | */ 23 | File getResultFile( String extension ); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/FileOutputFormat.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | public enum FileOutputFormat { 4 | 5 | PLAIN, 6 | ZIP, 7 | KRYO, 8 | CLOUD 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/GoldenMasterProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import java.io.File; 4 | 5 | import de.retest.recheck.ui.descriptors.SutState; 6 | 7 | public interface GoldenMasterProvider { 8 | 9 | /** 10 | * @param filePath 11 | * The file path to the Golden Master, relative to the project root. 12 | * @return The Golden Master file. 13 | * @throws NoGoldenMasterFoundException 14 | * If the Golden Master cannot be found. 15 | */ 16 | File getGoldenMaster( String filePath ) throws NoGoldenMasterFoundException; 17 | 18 | /** 19 | * @param file 20 | * The Golden Master file. 21 | * @return The {@code SutState} of the Golden Master. 22 | */ 23 | SutState loadGoldenMaster( File file ); 24 | 25 | /** 26 | * @param file 27 | * The Golden Master file. 28 | * @param state 29 | * The {@code SutState} of the Golden Master. 30 | */ 31 | void saveGoldenMaster( File file, SutState state ); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/GoldenMasterSourceSuppressDefaultAdapter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import de.retest.recheck.ui.review.GoldenMasterSource; 4 | import jakarta.xml.bind.annotation.adapters.XmlAdapter; 5 | 6 | public class GoldenMasterSourceSuppressDefaultAdapter extends XmlAdapter { 7 | 8 | @Override 9 | public GoldenMasterSource unmarshal( final GoldenMasterSource source ) throws Exception { 10 | if ( source == null ) { 11 | return GoldenMasterSource.RECORDED; 12 | } 13 | return source; 14 | } 15 | 16 | @Override 17 | public GoldenMasterSource marshal( final GoldenMasterSource source ) throws Exception { 18 | if ( source == GoldenMasterSource.RECORDED ) { 19 | return null; 20 | } 21 | return source; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/IncompatibleReportVersionException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import java.net.URI; 4 | 5 | import de.retest.recheck.ioerror.ReTestLoadException; 6 | 7 | public class IncompatibleReportVersionException extends ReTestLoadException { 8 | 9 | private static final String MESSAGE = 10 | "Incompatible recheck versions: report was written with %s, but read with %s."; 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | private final String writerVersion; 15 | private final String readerVersion; 16 | 17 | public IncompatibleReportVersionException( final String writerVersion, final String readerVersion, 18 | final URI location ) { 19 | super( location, String.format( MESSAGE, writerVersion, readerVersion ) ); 20 | this.writerVersion = writerVersion; 21 | this.readerVersion = readerVersion; 22 | } 23 | 24 | public IncompatibleReportVersionException( final String writerVersion, final String readerVersion, 25 | final URI location, final Throwable throwable ) { 26 | super( location, String.format( MESSAGE, writerVersion, readerVersion ), throwable ); 27 | this.writerVersion = writerVersion; 28 | this.readerVersion = readerVersion; 29 | } 30 | 31 | public String getWriterVersion() { 32 | return writerVersion; 33 | } 34 | 35 | public String getReaderVersion() { 36 | return readerVersion; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/MavenProjectLayout.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import static de.retest.recheck.RecheckProperties.RECHECK_FOLDER_NAME; 4 | 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | import java.util.Optional; 8 | 9 | /** 10 | * Maven-conform file namer that uses the following paths: 11 | *
    12 | *
  • Golden Master files: src/test/resources/retest/recheck/
  • 13 | *
  • Result files: target/test-classes/retest/recheck/
  • 14 | *
15 | */ 16 | public class MavenProjectLayout extends SeparatePathsProjectLayout { 17 | 18 | public static final String DEFAULT_RETEST_PROJECT_PATH = "src/test/resources/retest/"; 19 | public static final String DEFAULT_RETEST_TESTREPORTS_PATH = "target/test-classes/retest/"; 20 | 21 | public MavenProjectLayout() { 22 | super( Paths.get( DEFAULT_RETEST_PROJECT_PATH, RECHECK_FOLDER_NAME ), 23 | Paths.get( DEFAULT_RETEST_TESTREPORTS_PATH, RECHECK_FOLDER_NAME ) ); 24 | } 25 | 26 | @Override 27 | public Optional getTestSourcesRoot() { 28 | return Optional.of( Paths.get( "src/test/java" ) ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/NamingStrategy.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | /** 4 | * The naming strategy for both the Golden Master files and the report files. 5 | * 6 | * The NamingStrategy itself can come up with names for tests and suites. The default implementation 7 | * {@link ClassAndMethodBasedNamingStrategy} derives test suite and test case name from the test class and test method, 8 | * working for both JUnit and TestNG. 9 | */ 10 | public interface NamingStrategy { 11 | 12 | /** 13 | * Determines the suite name. In JUnit, for example, this is represented by the class name. 14 | * 15 | * @return name of the current test suite 16 | */ 17 | String getSuiteName(); 18 | 19 | /** 20 | * Determines the test name. In JUnit, for example, this is represented by the method name. 21 | * 22 | * @return name of the current test 23 | */ 24 | String getTestName(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/NoGoldenMasterFoundException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.Stream; 8 | 9 | import org.apache.commons.lang3.ArrayUtils; 10 | 11 | public class NoGoldenMasterFoundException extends Exception { 12 | 13 | private static final long serialVersionUID = 1L; 14 | 15 | private static final String GOLDEN_MASTER_PREFIX = "\n\t- "; 16 | 17 | private final List filenames; 18 | 19 | public NoGoldenMasterFoundException( final String... filenames ) { 20 | super( "The following Golden Master(s) cannot be found:" + listFilenames( filenames ) ); 21 | this.filenames = Arrays.asList( filenames ); 22 | } 23 | 24 | private static String listFilenames( final String[] filenames ) { 25 | if ( ArrayUtils.isEmpty( filenames ) ) { 26 | throw new IllegalArgumentException( "You should at least provide one Golden Master file." ); 27 | } 28 | return Stream.of( filenames ).collect( Collectors.joining( GOLDEN_MASTER_PREFIX, GOLDEN_MASTER_PREFIX, "" ) ); 29 | } 30 | 31 | public List getFilenames() { 32 | return Collections.unmodifiableList( filenames ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/Persistable.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import java.io.Serializable; 4 | 5 | public abstract class Persistable implements Serializable { 6 | 7 | private static final long serialVersionUID = 1L; 8 | private final int persistenceVersion; 9 | 10 | public Persistable( final int persistenceVersion ) { 11 | this.persistenceVersion = persistenceVersion; 12 | } 13 | 14 | public int version() { 15 | return persistenceVersion; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/Persistence.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import java.io.IOException; 4 | import java.net.URI; 5 | 6 | public interface Persistence { 7 | 8 | /** 9 | * @param identifier 10 | * URI on which it should be persisted 11 | * @param element 12 | * element to be persisted 13 | * @throws IOException 14 | * if an {@code IOException} occurs 15 | */ 16 | void save( URI identifier, T element ) throws IOException; 17 | 18 | /** 19 | * @param identifier 20 | * URI on which it should be persisted 21 | * @return loaded object, otherwise null 22 | * @throws IOException 23 | * if an {@code IOException} occurs 24 | */ 25 | T load( URI identifier ) throws IOException; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/migration/MigrationPairs.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.migration; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.apache.commons.lang3.tuple.ImmutablePair; 7 | import org.apache.commons.lang3.tuple.Pair; 8 | 9 | class MigrationPairs { 10 | 11 | private final List> oldVersionToXSLT = new ArrayList<>(); 12 | 13 | public MigrationPairs add( final int version, final XmlTransformer transformer ) { 14 | oldVersionToXSLT.add( new ImmutablePair<>( version, transformer ) ); 15 | return this; 16 | } 17 | 18 | /** 19 | * When renaming a root element class, we must add all migrations of the new class to the old class as well. This 20 | * function is designed for this. 21 | */ 22 | public MigrationPairs addAll( final List> migrations ) { 23 | oldVersionToXSLT.addAll( migrations ); 24 | return this; 25 | } 26 | 27 | public List> toList() { 28 | return oldVersionToXSLT; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/xml/XmlPersistenceUtil.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.xml; 2 | 3 | import java.io.IOException; 4 | 5 | import de.retest.recheck.persistence.Persistable; 6 | import de.retest.recheck.persistence.migration.XmlMigrator; 7 | import de.retest.recheck.persistence.xml.util.XmlVersionCheckResult; 8 | import de.retest.recheck.util.NamedBufferedInputStream; 9 | import jakarta.xml.bind.Unmarshaller.Listener; 10 | 11 | public class XmlPersistenceUtil { 12 | 13 | private XmlPersistenceUtil() {} 14 | 15 | static ReTestXmlDataContainer migrateAndRead( final XmlTransformer xml, 16 | final NamedBufferedInputStream inputStream, final Listener unmarshallListener ) throws IOException { 17 | NamedBufferedInputStream bin = inputStream; 18 | 19 | final XmlVersionCheckResult checkResult = XmlVersionCheckResult.create( bin ); 20 | 21 | if ( checkResult.newDataTypeInstance == null ) { 22 | throw new RuntimeException( "Unexpected data type " + checkResult.oldDataType ); 23 | } 24 | 25 | if ( !checkResult.isCompatible() ) { 26 | bin = XmlMigrator.tryToMigrate( checkResult, bin ); 27 | if ( bin == null ) { 28 | throw new RuntimeException( "Could not migrate XML." ); 29 | } 30 | } 31 | 32 | return xml.fromXML( bin, unmarshallListener ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/xml/XmlTransformerConfiguration.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.xml; 2 | 3 | import de.retest.recheck.persistence.xml.util.XmlUtil; 4 | import jakarta.xml.bind.Marshaller; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | 8 | @Builder 9 | @Data 10 | public class XmlTransformerConfiguration { 11 | 12 | /** 13 | * @see XmlUtil#addLightWeightAdapter(Marshaller) 14 | */ 15 | @Builder.Default 16 | private final boolean lightweightXml = false; 17 | /** 18 | * @see Marshaller#JAXB_FRAGMENT 19 | */ 20 | @Builder.Default 21 | private final boolean onlyFragment = false; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/persistence/xml/util/XmlUtil.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.xml.util; 2 | 3 | import de.retest.recheck.ui.descriptors.IdentifyingAttributesAdapter; 4 | import de.retest.recheck.ui.descriptors.RenderContainedElementsAdapter; 5 | import de.retest.recheck.ui.descriptors.StateAttributesAdapter; 6 | import jakarta.xml.bind.Marshaller; 7 | 8 | public class XmlUtil { 9 | 10 | private XmlUtil() {} 11 | 12 | public static String clean( final Object input ) { 13 | if ( input == null ) { 14 | return null; 15 | } 16 | String result = input.toString().trim(); 17 | result = result.replace( "&", "&" ); 18 | result = result.replace( "<", "<" ); 19 | result = result.replace( ">", ">" ); 20 | return result.replace( "\"", "'" ); 21 | } 22 | 23 | public static void addLightWeightAdapter( final Marshaller marshaller ) { 24 | marshaller.setAdapter( new RenderContainedElementsAdapter( true ) ); 25 | marshaller.setAdapter( new StateAttributesAdapter( true ) ); 26 | marshaller.setAdapter( new IdentifyingAttributesAdapter( true ) ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/AttributesDifferencePrinter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer; 2 | 3 | import java.util.stream.Collectors; 4 | 5 | import de.retest.recheck.printer.highlighting.DefaultHighlighter; 6 | import de.retest.recheck.printer.highlighting.Highlighter; 7 | import de.retest.recheck.ui.DefaultValueFinder; 8 | import de.retest.recheck.ui.descriptors.IdentifyingAttributes; 9 | import de.retest.recheck.ui.diff.AttributesDifference; 10 | 11 | public class AttributesDifferencePrinter implements Printer { 12 | 13 | private final AttributeDifferencePrinter delegate; 14 | 15 | public AttributesDifferencePrinter( final IdentifyingAttributes attributes, final DefaultValueFinder finder ) { 16 | this( attributes, finder, new DefaultHighlighter() ); 17 | } 18 | 19 | public AttributesDifferencePrinter( final IdentifyingAttributes attributes, final DefaultValueFinder finder, 20 | final Highlighter highlighter ) { 21 | delegate = new AttributeDifferencePrinter( attributes, finder, highlighter ); 22 | } 23 | 24 | @Override 25 | public String toString( final AttributesDifference difference, final String indent ) { 26 | return difference.getDifferences().stream() // 27 | .map( d -> delegate.toString( d, indent ) ) // 28 | .collect( Collectors.joining( "\n" ) ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/DefaultValueFinderProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer; 2 | 3 | import de.retest.recheck.ui.DefaultValueFinder; 4 | 5 | @FunctionalInterface 6 | public interface DefaultValueFinderProvider { 7 | 8 | DefaultValueFinder findForAction( String name ); 9 | 10 | static DefaultValueFinderProvider none() { 11 | final DefaultValueFinder noDefaults = ( attributes, key, value ) -> false; 12 | return name -> noDefaults; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/InsertedDeletedElementDifferencePrinter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer; 2 | 3 | import de.retest.recheck.ui.diff.InsertedDeletedElementDifference; 4 | 5 | public class InsertedDeletedElementDifferencePrinter implements Printer { 6 | 7 | @Override 8 | public String toString( final InsertedDeletedElementDifference difference, final String indent ) { 9 | return indent + (difference.isInserted() ? "was inserted" : "was deleted"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/Printer.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer; 2 | 3 | @FunctionalInterface 4 | public interface Printer { 5 | 6 | default String toString( final D difference ) { 7 | return toString( difference, "" ); 8 | } 9 | 10 | String toString( D difference, final String indent ); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/TestReportPrinter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer; 2 | 3 | import java.util.stream.Collectors; 4 | 5 | import de.retest.recheck.printer.highlighting.DefaultHighlighter; 6 | import de.retest.recheck.printer.highlighting.Highlighter; 7 | import de.retest.recheck.report.TestReport; 8 | 9 | public class TestReportPrinter implements Printer { 10 | 11 | private final SuiteReplayResultPrinter delegate; 12 | 13 | public TestReportPrinter( final DefaultValueFinderProvider provider ) { 14 | this( new SuiteReplayResultPrinter( provider, new DefaultHighlighter() ) ); 15 | } 16 | 17 | public TestReportPrinter( final DefaultValueFinderProvider provider, final Highlighter highlighter ) { 18 | this( new SuiteReplayResultPrinter( provider, highlighter ) ); 19 | } 20 | 21 | public TestReportPrinter( final SuiteReplayResultPrinter delegate ) { 22 | this.delegate = delegate; 23 | } 24 | 25 | @Override 26 | public String toString( final TestReport testReport, final String indent ) { 27 | if ( testReport.isEmpty() ) { 28 | return "No differences found."; 29 | } 30 | return testReport.getSuiteReplayResults().stream() // 31 | .filter( suiteReplayResult -> !suiteReplayResult.isEmpty() ) // 32 | .map( suiteReplayResult -> delegate.toString( suiteReplayResult, indent ) ) // 33 | .collect( Collectors.joining( "\n" ) ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/highlighting/DefaultHighlighter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer.highlighting; 2 | 3 | public class DefaultHighlighter implements Highlighter { 4 | 5 | @Override 6 | public String highlight( final String msg, final HighlightType element ) { 7 | // DefaultHighlighter does not apply any highlighting to the (string) printers 8 | return msg; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/highlighting/HighlightType.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer.highlighting; 2 | 3 | public enum HighlightType { 4 | ACTUAL, 5 | KEY, 6 | EXPECTED, 7 | HEADING_SUITE_RESULTS, 8 | HEADING_METADATA, 9 | PATH, 10 | TYPE, 11 | ELEMENT, 12 | VALUE_EXPECTED, 13 | VALUE_ACTUAL, 14 | NOTE, 15 | TESTREPLAYRESULT_NAME 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/highlighting/Highlighter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer.highlighting; 2 | 3 | @FunctionalInterface 4 | public interface Highlighter { 5 | String highlight( String msg, HighlightType element ); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/printer/highlighting/UnsupportedHighlightTypeException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer.highlighting; 2 | 3 | public class UnsupportedHighlightTypeException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public UnsupportedHighlightTypeException( final String message ) { 8 | super( message ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/report/action/DifferenceRetriever.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.report.action; 2 | 3 | import java.util.Collections; 4 | 5 | import de.retest.recheck.ui.diff.StateDifference; 6 | import de.retest.recheck.ui.diff.meta.MetadataDifference; 7 | 8 | public interface DifferenceRetriever { 9 | 10 | StateDifference getStateDifference(); 11 | 12 | MetadataDifference getMetadataDifference(); 13 | 14 | default boolean isNull() { 15 | return getStateDifference() == null || getStateDifference().size() == 0; 16 | } 17 | 18 | static DifferenceRetriever empty() { 19 | return of( new StateDifference( Collections.emptyList() ) ); 20 | } 21 | 22 | static DifferenceRetriever of( final StateDifference stateDifference ) { 23 | return of( stateDifference, MetadataDifference.empty() ); 24 | } 25 | 26 | static DifferenceRetriever of( final MetadataDifference metadataDifference ) { 27 | return of( new StateDifference( Collections.emptyList() ), metadataDifference ); 28 | } 29 | 30 | static DifferenceRetriever of( final StateDifference stateDifference, 31 | final MetadataDifference metadataDifference ) { 32 | return new DifferenceRetriever() { 33 | 34 | @Override 35 | public StateDifference getStateDifference() { 36 | return stateDifference; 37 | } 38 | 39 | @Override 40 | public MetadataDifference getMetadataDifference() { 41 | return metadataDifference; 42 | } 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/report/action/WindowRetriever.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.report.action; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.function.Supplier; 6 | 7 | import de.retest.recheck.ui.actions.ActionState; 8 | import de.retest.recheck.ui.descriptors.RootElement; 9 | import de.retest.recheck.ui.descriptors.SutState; 10 | 11 | @FunctionalInterface 12 | public interface WindowRetriever extends Supplier> { 13 | 14 | default boolean isNull() { 15 | return get() == null; 16 | } 17 | 18 | static WindowRetriever empty() { 19 | return Collections::emptyList; 20 | } 21 | 22 | static WindowRetriever of( final List elements ) { 23 | return () -> elements; 24 | } 25 | 26 | static WindowRetriever of( final SutState state ) { 27 | return state::getRootElements; 28 | } 29 | 30 | static WindowRetriever of( final ActionState state ) { 31 | return of( state.getState() ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/counter/Counter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.counter; 2 | 3 | public interface Counter { 4 | 5 | void add(); 6 | 7 | void remove(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/counter/IntCounter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.counter; 2 | 3 | import java.util.function.IntConsumer; 4 | 5 | public class IntCounter implements Counter { 6 | 7 | private int count = 0; 8 | 9 | private final IntConsumer listener; 10 | 11 | public IntCounter( final IntConsumer listener ) { 12 | this.listener = listener; 13 | this.listener.accept( count ); 14 | } 15 | 16 | @Override 17 | public void add() { 18 | count += 1; 19 | listener.accept( count ); 20 | } 21 | 22 | @Override 23 | public void remove() { 24 | count -= 1; 25 | listener.accept( count ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/counter/NopCounter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.counter; 2 | 3 | public class NopCounter implements Counter { 4 | 5 | private static final Counter INSTANCE = new NopCounter(); 6 | 7 | public static Counter getInstance() { 8 | return INSTANCE; 9 | } 10 | 11 | private NopCounter() {} 12 | 13 | @Override 14 | public void add() { 15 | // do nothing 16 | } 17 | 18 | @Override 19 | public void remove() { 20 | // do nothing 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/ignore/ElementFilter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore; 2 | 3 | import de.retest.recheck.review.ignore.matcher.Matcher; 4 | import de.retest.recheck.ui.descriptors.Element; 5 | 6 | /** 7 | * Use {@link MatcherFilter} instead. 8 | */ 9 | // TODO Remove for a 2.0 release 10 | @Deprecated 11 | public class ElementFilter extends MatcherFilter { 12 | 13 | public ElementFilter( final Matcher matcher ) { 14 | super( matcher ); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/ignore/JSFilterLoader.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore; 2 | 3 | import java.util.Optional; 4 | 5 | import de.retest.recheck.ignore.JSFilterImpl; 6 | import de.retest.recheck.review.ignore.io.Loader; 7 | 8 | public class JSFilterLoader implements Loader { 9 | 10 | @Override 11 | public Optional load( final String line ) { 12 | // XXX This causes exceptions when something is loaded which other loaders can't load. 13 | return Optional.empty(); 14 | } 15 | 16 | @Override 17 | public String save( final JSFilterImpl ignore ) { 18 | return ""; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/ignore/io/ErrorHandlingLoader.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore.io; 2 | 3 | import java.util.Optional; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import de.retest.recheck.review.ignore.FilterPreserveLineLoader.FilterPreserveLine; 9 | 10 | public final class ErrorHandlingLoader implements Loader { 11 | 12 | private static final Logger logger = LoggerFactory.getLogger( ErrorHandlingLoader.class ); 13 | 14 | @Override 15 | public Optional load( final String line ) { 16 | if ( line.startsWith( "attribute:" ) ) { 17 | logger.error( 18 | "For ignoring an attribute globally, please use 'attribute=' (to ensure weired line breaks do not break your ignore file)." ); 19 | } else { 20 | logger.error( 21 | "No loader defined for line '{}'. Read more at https://docs.retest.de/recheck/how-ignore-works/", 22 | line ); 23 | } 24 | return Optional.of( new FilterPreserveLine( line ) ); 25 | } 26 | 27 | @Override 28 | public String save( final FilterPreserveLine errorLine ) { 29 | return errorLine.toString(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/ignore/io/Loader.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore.io; 2 | 3 | import java.util.Optional; 4 | import java.util.stream.Stream; 5 | 6 | import de.retest.recheck.util.OptionalUtil; 7 | 8 | public interface Loader { 9 | 10 | Optional load( String line ); 11 | 12 | default Stream load( final Stream lines ) { 13 | return lines.map( this::load ) // 14 | .flatMap( OptionalUtil::stream ); 15 | } 16 | 17 | String save( T ignore ); 18 | 19 | default Stream save( final Stream objects ) { 20 | return objects.map( this::save ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/ignore/io/RegexLoader.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore.io; 2 | 3 | import java.util.Optional; 4 | import java.util.regex.MatchResult; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | public abstract class RegexLoader implements Loader { 9 | 10 | private final Pattern regex; 11 | 12 | public RegexLoader( final Pattern regex ) { 13 | this.regex = regex; 14 | } 15 | 16 | @Override 17 | public Optional load( final String line ) { 18 | final Matcher matcher = regex.matcher( line ); 19 | if ( !matcher.matches() ) { 20 | return Optional.empty(); 21 | } 22 | return load( matcher.toMatchResult() ); 23 | } 24 | 25 | protected abstract Optional load( final MatchResult matcher ); 26 | 27 | @Override 28 | public String save( final T ignore ) { 29 | return ignore.toString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/review/ignore/matcher/Matcher.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore.matcher; 2 | 3 | import java.util.function.Predicate; 4 | 5 | public interface Matcher extends Predicate { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/suite/CapturedSuite.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.suite; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | import de.retest.recheck.persistence.Persistable; 7 | import jakarta.xml.bind.annotation.XmlAccessType; 8 | import jakarta.xml.bind.annotation.XmlAccessorType; 9 | import jakarta.xml.bind.annotation.XmlElement; 10 | import jakarta.xml.bind.annotation.XmlRootElement; 11 | 12 | @XmlRootElement 13 | @XmlAccessorType( XmlAccessType.FIELD ) 14 | public class CapturedSuite extends Persistable { 15 | 16 | private static final long serialVersionUID = 1L; 17 | private static final int PERSISTENCE_VERSION = 2; 18 | 19 | @XmlElement( name = "tests" ) 20 | private final ArrayList tests = new ArrayList<>(); 21 | 22 | public CapturedSuite() { 23 | super( PERSISTENCE_VERSION ); 24 | } 25 | 26 | public ArrayList getTests() { 27 | return tests; 28 | } 29 | 30 | public void addTest( final String relativeFilePath ) { 31 | tests.add( relativeFilePath ); 32 | } 33 | 34 | public void addTests( final String... testFileNames ) { 35 | Collections.addAll( tests, testFileNames ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/suite/ExecutionSuitesDoNotMatchException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.suite; 2 | 3 | public class ExecutionSuitesDoNotMatchException extends Exception { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public ExecutionSuitesDoNotMatchException( final String expectedUuid, final String actualUuid ) { 8 | super( "The given change set does not match this execsuite - has it already been updated? expectedUuid:" 9 | + expectedUuid + ", actualUuid:" + actualUuid ); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/test/Test.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.test; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import de.retest.recheck.persistence.Persistable; 8 | import jakarta.xml.bind.annotation.XmlAccessType; 9 | import jakarta.xml.bind.annotation.XmlAccessorType; 10 | import jakarta.xml.bind.annotation.XmlElement; 11 | import jakarta.xml.bind.annotation.XmlRootElement; 12 | 13 | @XmlRootElement 14 | @XmlAccessorType( XmlAccessType.FIELD ) 15 | public class Test extends Persistable { 16 | 17 | private static final long serialVersionUID = 1L; 18 | private static final int PERSISTENCE_VERSION = 2; 19 | 20 | @XmlElement( name = "relativeActionSequencePath" ) 21 | private final List relativeActionSequencePaths; 22 | 23 | @SuppressWarnings( "unused" ) // only for JAXB 24 | private Test() { 25 | this( new ArrayList() ); 26 | } 27 | 28 | public Test( final List relativeActionSequencePaths ) { 29 | super( PERSISTENCE_VERSION ); 30 | this.relativeActionSequencePaths = relativeActionSequencePaths; 31 | } 32 | 33 | public List getRelativeActionSequencePaths() { 34 | return Collections.unmodifiableList( relativeActionSequencePaths ); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/DefaultValueFinder.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui; 2 | 3 | import java.io.Serializable; 4 | 5 | import de.retest.recheck.ui.descriptors.IdentifyingAttributes; 6 | 7 | public interface DefaultValueFinder { 8 | 9 | /** 10 | * Checks if the combination of {@code identifyingAttributes}, {@code attributeKey}, and {@code attributeValue} 11 | * represents a default value. Default values are not persisted to save lots of memory and reduce noise. 12 | * 13 | * @param identifyingAttributes 14 | * identifying attributes 15 | * @param attributeKey 16 | * attribute key 17 | * @param attributeValue 18 | * attribute value 19 | * @return {@code true} if the value is a default 20 | */ 21 | boolean isDefaultValue( final IdentifyingAttributes identifyingAttributes, final String attributeKey, 22 | Serializable attributeValue ); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/IgnoredTypes.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui; 2 | 3 | import de.retest.recheck.ui.descriptors.Element; 4 | import de.retest.recheck.ui.descriptors.IdentifyingAttributes; 5 | 6 | /** 7 | * {@code RecheckIgnore} are user-specific and may change during runtime, whereas {@code IgnoredTypes} are 8 | * toolkit-specific and known at compile time. 9 | */ 10 | public interface IgnoredTypes { 11 | 12 | boolean contains( final Element element ); 13 | 14 | boolean contains( final IdentifyingAttributes identifyingAttributes ); 15 | 16 | public static class NoIgnoredTypes implements IgnoredTypes { 17 | @Override 18 | public boolean contains( final Element element ) { 19 | return false; 20 | } 21 | 22 | @Override 23 | public boolean contains( final IdentifyingAttributes identifyingAttributes ) { 24 | return false; 25 | } 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/PathAdapter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui; 2 | 3 | import jakarta.xml.bind.annotation.adapters.XmlAdapter; 4 | 5 | public class PathAdapter extends XmlAdapter { 6 | 7 | @Override 8 | public Path unmarshal( final String string ) throws Exception { 9 | return Path.fromString( string ); 10 | } 11 | 12 | @Override 13 | public String marshal( final Path path ) throws Exception { 14 | return path.toString(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/actions/Action.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.actions; 2 | 3 | import java.io.Serializable; 4 | 5 | import de.retest.recheck.ui.Environment; 6 | import de.retest.recheck.ui.components.Component; 7 | import de.retest.recheck.ui.descriptors.Element; 8 | import de.retest.recheck.ui.image.Screenshot; 9 | import de.retest.recheck.ui.review.ActionChangeSet; 10 | import jakarta.xml.bind.annotation.XmlTransient; 11 | 12 | public interface Action extends Serializable, Comparable { 13 | 14 | Action randomize(); 15 | 16 | /** 17 | * Executes this action in the given environment. Returns a {@link Throwable} if this causes an exception within the 18 | * SUT. 19 | * 20 | * @param 21 | * the enviroment type 22 | * 23 | * @param environment 24 | * enviroment in which the action will be executed 25 | * 26 | * @return the result of the execution 27 | */ 28 | ActionExecutionResult execute( Environment environment ); 29 | 30 | void execute( Component component ) throws TargetNotFoundException; 31 | 32 | Element getTargetElement(); 33 | 34 | @Override 35 | int hashCode(); 36 | 37 | Screenshot[] getWindowsScreenshots(); 38 | 39 | @XmlTransient 40 | void setWindowsScreenshots( Screenshot[] windowsScreenshots ); 41 | 42 | String getUuid(); 43 | 44 | Action applyChanges( ActionChangeSet reviewResult ); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/actions/ActionList.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.actions; 2 | 3 | import java.util.EventObject; 4 | 5 | public interface ActionList { 6 | 7 | void addAction( Action action, EventObject eo ); 8 | 9 | Action getLastAction(); 10 | 11 | public abstract class ActionListStub implements ActionList { 12 | private Action last; 13 | 14 | @Override 15 | public void addAction( final Action action, final EventObject eo ) { 16 | last = action; 17 | addAction( action ); 18 | } 19 | 20 | public abstract void addAction( Action action ); 21 | 22 | @Override 23 | public Action getLastAction() { 24 | return last; 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/actions/ValueProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.actions; 2 | 3 | public interface ValueProvider { 4 | 5 | String get( String key ); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/components/ComponentContainer.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.components; 2 | 3 | import de.retest.recheck.ui.descriptors.IdentifyingAttributes; 4 | 5 | public interface ComponentContainer extends Component { 6 | 7 | String getTextWithComponents(); 8 | 9 | java.util.List> getTargetableComponents(); 10 | 11 | /** 12 | * @return All components, deeply retrieved. 13 | */ 14 | java.util.List> getAllComponents(); 15 | 16 | /** 17 | * @return Only direct child components (of the next deeper level). 18 | */ 19 | java.util.List> getChildComponents(); 20 | 21 | Component getPeerComponent( T component ); 22 | 23 | Component getBestMatch( IdentifyingAttributes identifyingAttributes ); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/components/RootContainer.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.components; 2 | 3 | import de.retest.recheck.ui.descriptors.RootElement; 4 | 5 | public interface RootContainer extends ComponentContainer { 6 | 7 | RootElement getRootElement(); 8 | 9 | String getScreenId(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/AdditionalAttributeDifference.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import de.retest.recheck.ui.diff.AttributeDifference; 4 | import jakarta.xml.bind.annotation.XmlAccessType; 5 | import jakarta.xml.bind.annotation.XmlAccessorType; 6 | import jakarta.xml.bind.annotation.XmlRootElement; 7 | 8 | @XmlRootElement 9 | @XmlAccessorType( XmlAccessType.FIELD ) 10 | public class AdditionalAttributeDifference extends AttributeDifference { 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | // for JAXB 15 | protected AdditionalAttributeDifference() {} 16 | 17 | public AdditionalAttributeDifference( final String key, final Attribute attribute ) { 18 | super( key, null, attribute ); 19 | } 20 | 21 | @Override 22 | public Attribute applyChangeTo( final Attribute attribute ) { 23 | return (Attribute) getActual(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/CodeLocAttribute.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.io.Serializable; 4 | 5 | import jakarta.xml.bind.annotation.XmlRootElement; 6 | 7 | @XmlRootElement 8 | public class CodeLocAttribute extends TextAttribute { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private static final String CODE_LOC_KEY = "codeLoc"; 13 | 14 | // Used by JaxB 15 | @SuppressWarnings( "unused" ) 16 | private CodeLocAttribute() {} 17 | 18 | public CodeLocAttribute( final String codeLoc ) { 19 | this( codeLoc, null ); 20 | } 21 | 22 | public CodeLocAttribute( final String codeLoc, final String variableName ) { 23 | super( CODE_LOC_KEY, codeLoc != null && !"[]".equals( codeLoc ) ? codeLoc : null, variableName ); 24 | } 25 | 26 | @Override 27 | public String getValue() { 28 | final Serializable value = super.getValue(); 29 | return value != null && !"[]".equals( value ) ? (String) value : null; 30 | } 31 | 32 | @Override 33 | public boolean isVisible() { 34 | return false; 35 | } 36 | 37 | @Override 38 | public Attribute applyChanges( final Serializable actual ) { 39 | return new CodeLocAttribute( (String) actual, getVariableName() ); 40 | } 41 | 42 | @Override 43 | public ParameterizedAttribute applyVariableChange( final String variableName ) { 44 | return new CodeLocAttribute( getValue(), variableName ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/ContextAttribute.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.io.Serializable; 4 | 5 | import jakarta.xml.bind.annotation.XmlRootElement; 6 | 7 | @XmlRootElement 8 | public class ContextAttribute extends StringAttribute { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private static final String CONTEXT_KEY = "context"; 13 | 14 | // Used by JaxB 15 | protected ContextAttribute() {} 16 | 17 | public ContextAttribute( final String value ) { 18 | super( CONTEXT_KEY, value ); 19 | } 20 | 21 | public ContextAttribute( final String value, final String variableName ) { 22 | super( CONTEXT_KEY, value, variableName ); 23 | } 24 | 25 | @Override 26 | public double getWeight() { 27 | return Attribute.IGNORE_WEIGHT; 28 | } 29 | 30 | @Override 31 | public Attribute applyChanges( final Serializable actual ) { 32 | return new ContextAttribute( (String) actual, getVariableName() ); 33 | } 34 | 35 | @Override 36 | public ParameterizedAttribute applyVariableChange( final String variableName ) { 37 | return new ContextAttribute( getValue(), variableName ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/ElementUtil.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class ElementUtil { 7 | 8 | private ElementUtil() {} 9 | 10 | public static List flattenAllElements( final List elements ) { 11 | final List flattened = new ArrayList<>(); 12 | 13 | for ( final Element element : elements ) { 14 | flattened.add( element ); 15 | flattened.addAll( flattenChildElements( element ) ); 16 | } 17 | 18 | return flattened; 19 | } 20 | 21 | public static List flattenChildElements( final Element element ) { 22 | final List flattened = new ArrayList<>(); 23 | 24 | for ( final Element childElement : element.getContainedElements() ) { 25 | flattened.add( childElement ); 26 | flattened.addAll( flattenChildElements( childElement ) ); 27 | } 28 | 29 | return flattened; 30 | } 31 | 32 | public static boolean pathEquals( final Element element0, final Element element1 ) { 33 | return element0.getIdentifyingAttributes().getPathTyped() 34 | .equals( element1.getIdentifyingAttributes().getPathTyped() ); 35 | } 36 | 37 | public static boolean retestIdEquals( final Element element0, final Element element1 ) { 38 | return element0.getRetestId().equals( element1.getRetestId() ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/IdentifyingAttributesAdapter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import jakarta.xml.bind.annotation.adapters.XmlAdapter; 4 | 5 | public class IdentifyingAttributesAdapter extends XmlAdapter { 6 | 7 | private final boolean renderLightweightXml; 8 | 9 | public IdentifyingAttributesAdapter() { 10 | renderLightweightXml = false; 11 | } 12 | 13 | public IdentifyingAttributesAdapter( final boolean renderLightweightXml ) { 14 | this.renderLightweightXml = renderLightweightXml; 15 | } 16 | 17 | @Override 18 | public IdentifyingAttributes marshal( final IdentifyingAttributes identifyingAttributes ) throws Exception { 19 | return renderLightweightXml ? null : identifyingAttributes; 20 | } 21 | 22 | @Override 23 | public IdentifyingAttributes unmarshal( final IdentifyingAttributes identifyingAttributes ) throws Exception { 24 | return identifyingAttributes; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/MutableAttributes.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.util.TreeMap; 4 | 5 | import de.retest.recheck.ui.image.Screenshot; 6 | 7 | public class MutableAttributes { 8 | final TreeMap attributes; 9 | 10 | public MutableAttributes() { 11 | attributes = new TreeMap<>(); 12 | } 13 | 14 | public MutableAttributes( final Attributes attributes ) { 15 | this.attributes = new TreeMap<>( attributes.getMap() ); 16 | } 17 | 18 | public Attributes immutable() { 19 | return new Attributes( this ); 20 | } 21 | 22 | public void put( final String name, final String criterion ) { 23 | attributes.put( name, criterion ); 24 | } 25 | 26 | public void put( final String name, final Integer criterion ) { 27 | attributes.put( name, criterion ); 28 | } 29 | 30 | public void put( final String name, final Boolean criterion ) { 31 | attributes.put( name, criterion ); 32 | } 33 | 34 | public Object get( final String name ) { 35 | return attributes.get( name ); 36 | } 37 | 38 | public void put( final Screenshot screenshot ) { 39 | attributes.put( Attributes.SCREENSHOT, screenshot ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/ParameterParseException.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | public class ParameterParseException extends Exception { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public ParameterParseException( final String msg, final Exception exc ) { 8 | super( msg, exc ); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/ParameterizedAttribute.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import jakarta.xml.bind.annotation.XmlAttribute; 6 | import jakarta.xml.bind.annotation.XmlRootElement; 7 | 8 | @XmlRootElement 9 | public abstract class ParameterizedAttribute extends Attribute { 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | @XmlAttribute 14 | private final String variableName; 15 | 16 | // Used by JaxB 17 | protected ParameterizedAttribute() { 18 | variableName = null; 19 | } 20 | 21 | public ParameterizedAttribute( final String key, final String variableName ) { 22 | super( key ); 23 | this.variableName = StringUtils.isNotEmpty( variableName ) ? variableName : null; 24 | } 25 | 26 | public String getVariableName() { 27 | return variableName; 28 | } 29 | 30 | public abstract ParameterizedAttribute applyVariableChange( final String variableName ); 31 | 32 | public abstract ParameterType getType(); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/ParseStringAttributeDifference.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.io.Serializable; 4 | 5 | import de.retest.recheck.ui.diff.AttributeDifference; 6 | 7 | public class ParseStringAttributeDifference extends AttributeDifference { 8 | 9 | private static final long serialVersionUID = 1L; 10 | 11 | public ParseStringAttributeDifference( final ParameterizedAttribute attribute, final String actual ) { 12 | super( attribute.getKey(), attribute.getValue(), actual ); 13 | } 14 | 15 | @Override 16 | public Attribute applyChangeTo( final Attribute attribute ) { 17 | if ( attribute instanceof ParameterizedAttribute ) { 18 | final String actual = (String) getActual(); 19 | try { 20 | final ParameterizedAttribute param = (ParameterizedAttribute) attribute; 21 | final ParameterType type = param.getType(); 22 | final Serializable value = (Serializable) type.parse( actual ); 23 | return attribute.applyChanges( value ); 24 | } catch ( final Exception e ) { /* ignore */ } 25 | } 26 | return attribute; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/RenderContainedElementsAdapter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import jakarta.xml.bind.annotation.adapters.XmlAdapter; 7 | 8 | public class RenderContainedElementsAdapter extends XmlAdapter { 9 | 10 | private final boolean renderLightweightXml; 11 | 12 | public RenderContainedElementsAdapter() { 13 | renderLightweightXml = false; 14 | } 15 | 16 | public RenderContainedElementsAdapter( final boolean renderLightweightXml ) { 17 | this.renderLightweightXml = renderLightweightXml; 18 | } 19 | 20 | @Override 21 | public Element marshal( final Element descriptor ) throws Exception { 22 | if ( descriptor instanceof RootElement ) { 23 | return descriptor; 24 | } 25 | return renderLightweightXml ? null : descriptor; 26 | } 27 | 28 | private final Map elements = new HashMap<>(); 29 | 30 | @Override 31 | public Element unmarshal( final Element descriptor ) throws Exception { 32 | if ( descriptor.identifyingAttributes == null ) { 33 | return descriptor; 34 | } 35 | 36 | if ( elements.containsKey( descriptor ) ) { 37 | return elements.get( descriptor ); 38 | } 39 | 40 | elements.put( descriptor, descriptor ); 41 | return descriptor; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/StateAttributesAdapter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import jakarta.xml.bind.annotation.adapters.XmlAdapter; 4 | 5 | public class StateAttributesAdapter extends XmlAdapter { 6 | 7 | private final boolean renderLightweightXml; 8 | 9 | public StateAttributesAdapter() { 10 | renderLightweightXml = false; 11 | } 12 | 13 | public StateAttributesAdapter( final boolean renderLightweightXml ) { 14 | this.renderLightweightXml = renderLightweightXml; 15 | } 16 | 17 | @Override 18 | public Attributes marshal( final Attributes attributes ) throws Exception { 19 | return renderLightweightXml ? null : attributes; 20 | } 21 | 22 | @Override 23 | public Attributes unmarshal( final Attributes attributes ) throws Exception { 24 | return attributes; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/TextAttribute.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.io.Serializable; 4 | 5 | import de.retest.recheck.util.StringSimilarity; 6 | import jakarta.xml.bind.annotation.XmlRootElement; 7 | 8 | @XmlRootElement 9 | public class TextAttribute extends StringAttribute { 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | // Used by JaxB 14 | protected TextAttribute() {} 15 | 16 | public TextAttribute( final String key, final String value ) { 17 | this( key, value, null ); 18 | } 19 | 20 | public TextAttribute( final String key, final String value, final String variableName ) { 21 | super( key, value, variableName ); 22 | } 23 | 24 | @Override 25 | public double match( final Attribute other ) { 26 | if ( !(other instanceof TextAttribute) ) { 27 | return NO_MATCH; 28 | } 29 | assert other.getKey().equals( getKey() ); 30 | return StringSimilarity.textSimilarity( getValue(), ((StringAttribute) other).getValue() ); 31 | } 32 | 33 | @Override 34 | public Attribute applyChanges( final Serializable actual ) { 35 | return new TextAttribute( getKey(), (String) actual, getVariableName() ); 36 | } 37 | 38 | @Override 39 | public ParameterizedAttribute applyVariableChange( final String variableName ) { 40 | return new TextAttribute( getKey(), getValue(), variableName ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/VariableNameAttributeDifference.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import de.retest.recheck.ui.diff.AttributeDifference; 4 | 5 | public class VariableNameAttributeDifference extends AttributeDifference { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | public VariableNameAttributeDifference( final ParameterizedAttribute attribute, final String variableName ) { 10 | super( attribute.getKey(), attribute.getVariableName(), variableName ); 11 | } 12 | 13 | @Override 14 | public Attribute applyChangeTo( final Attribute attribute ) { 15 | if ( attribute instanceof ParameterizedAttribute ) { 16 | final ParameterizedAttribute parameterizedAttribute = (ParameterizedAttribute) attribute; 17 | warnIfAttributesDontMatch( parameterizedAttribute.getVariableName() ); 18 | return parameterizedAttribute.applyVariableChange( (String) getActual() ); 19 | } 20 | return attribute; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/WeightedTextAttribute.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import java.io.Serializable; 4 | 5 | import jakarta.xml.bind.annotation.XmlRootElement; 6 | 7 | @XmlRootElement 8 | public final class WeightedTextAttribute extends TextAttribute { 9 | 10 | /** 11 | * Text weight for similarity. 12 | */ 13 | public static final double TEXT_WEIGHT = 1.5; 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | // Used by JaxB 18 | @SuppressWarnings( "unused" ) 19 | private WeightedTextAttribute() {} 20 | 21 | public WeightedTextAttribute( final String key, final String value ) { 22 | this( key, value, null ); 23 | } 24 | 25 | public WeightedTextAttribute( final String key, final String value, final String variableName ) { 26 | super( key, value, variableName ); 27 | } 28 | 29 | @Override 30 | public double getWeight() { 31 | return TEXT_WEIGHT; 32 | } 33 | 34 | @Override 35 | public Attribute applyChanges( final Serializable actual ) { 36 | return new WeightedTextAttribute( getKey(), (String) actual, getVariableName() ); 37 | } 38 | 39 | @Override 40 | public ParameterizedAttribute applyVariableChange( final String variableName ) { 41 | return new WeightedTextAttribute( getKey(), getValue(), variableName ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/idproviders/ConsistentRetestIdProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors.idproviders; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import de.retest.recheck.ui.descriptors.IdentifyingAttributes; 7 | 8 | public final class ConsistentRetestIdProvider implements RetestIdProvider { 9 | 10 | private final RetestIdProvider delegate; 11 | private final Map consistency = new HashMap<>(); 12 | 13 | public ConsistentRetestIdProvider( final RetestIdProvider delegate ) { 14 | this.delegate = delegate; 15 | } 16 | 17 | @Override 18 | public String getRetestId( final IdentifyingAttributes identifyingAttributes ) { 19 | String result = consistency.get( identifyingAttributes.identifier() ); 20 | if ( result != null ) { 21 | return result; 22 | } 23 | result = delegate.getRetestId( identifyingAttributes ); 24 | while ( consistency.containsValue( result ) ) { 25 | result = delegate.getRetestId( identifyingAttributes ); 26 | } 27 | consistency.put( identifyingAttributes.identifier(), result ); 28 | return result; 29 | } 30 | 31 | @Override 32 | public void reset() { 33 | // We do not reset our consistency, this is the whole point of it... 34 | delegate.reset(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/idproviders/DefaultRetestIdProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors.idproviders; 2 | 3 | import de.retest.recheck.ui.descriptors.IdentifyingAttributes; 4 | 5 | public final class DefaultRetestIdProvider implements RetestIdProvider { 6 | 7 | private final RetestIdProvider delegate = new ElementCountingRetestIdProvider(); 8 | 9 | @Override 10 | public String getRetestId( final IdentifyingAttributes identifyingAttributes ) { 11 | return delegate.getRetestId( identifyingAttributes ); 12 | } 13 | 14 | @Override 15 | public void reset() { 16 | delegate.reset(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/descriptors/idproviders/ElementCountingRetestIdProvider.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors.idproviders; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Use the first non-null, non-blank of native id attribute, text or type to create a unique retestId. If the id, text 8 | * or type already exists, use a random suffix to make it unique. 9 | */ 10 | public final class ElementCountingRetestIdProvider extends AbstractFirstNonNullRetestIdProvider { 11 | 12 | private final Map counter = new HashMap<>(); 13 | 14 | @Override 15 | protected String makeUnique( final String id ) { 16 | final Integer result = counter.get( id ); 17 | if ( result == null ) { 18 | counter.put( id, 1 ); 19 | return id; 20 | } 21 | counter.put( id, result + 1 ); 22 | return id + DELIMITER + result; 23 | } 24 | 25 | @Override 26 | public void reset() { 27 | counter.clear(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/diff/Difference.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.diff; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | public interface Difference extends Serializable { 7 | 8 | int size(); 9 | 10 | /** 11 | * @return non-empty differences for attribute and identifying attribute differences as well as non-empty child 12 | * differences 13 | */ 14 | List getNonEmptyDifferences(); 15 | 16 | /** 17 | * @return all differences for attribute and identifying attribute differences as well as all child differences 18 | */ 19 | List getElementDifferences(); 20 | 21 | @Override 22 | String toString(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/diff/LeafDifference.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.diff; 2 | 3 | import java.io.Serializable; 4 | 5 | public interface LeafDifference extends Difference { 6 | 7 | Serializable getActual(); 8 | 9 | Serializable getExpected(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/diff/Match.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.diff; 2 | 3 | import de.retest.recheck.ui.descriptors.Element; 4 | 5 | public class Match implements Comparable { 6 | 7 | final double similarity; 8 | final Element element; 9 | 10 | public static Match of( final double similarity, final Element element ) { 11 | return new Match( similarity, element ); 12 | } 13 | 14 | public static Match ofEqual( final Element element ) { 15 | return new Match( 1.0, element ); 16 | } 17 | 18 | private Match( final double similarity, final Element element ) { 19 | this.similarity = similarity; 20 | this.element = element; 21 | } 22 | 23 | @Override 24 | public int compareTo( final Match o ) { 25 | final int result = Double.compare( o.similarity, similarity ); 26 | // same similarity should not be overwritten in the Tree 27 | if ( result == 0 ) { 28 | return -1; 29 | } 30 | return result; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "Match[similarity='" + similarity + "', element='" + element + "']"; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/diff/meta/MetadataElementDifference.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.diff.meta; 2 | 3 | import java.io.Serializable; 4 | 5 | import lombok.Value; 6 | 7 | @Value 8 | public class MetadataElementDifference implements Serializable { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private final String key; 13 | private final String expected; 14 | private final String actual; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/ui/review/GoldenMasterSource.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.review; 2 | 3 | public enum GoldenMasterSource { 4 | RECORDED, 5 | API; 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/util/DeleteOnCloseFileInputStream.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | 8 | import org.apache.commons.io.FileUtils; 9 | 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /* 13 | * Taken from https://stackoverflow.com/a/4694155 14 | */ 15 | @Slf4j 16 | public class DeleteOnCloseFileInputStream extends FileInputStream { 17 | 18 | private final File file; 19 | 20 | public DeleteOnCloseFileInputStream( final File file ) throws FileNotFoundException { 21 | super( file ); 22 | this.file = file; 23 | } 24 | 25 | @Override 26 | public void close() throws IOException { 27 | try { 28 | super.close(); 29 | } finally { 30 | if ( file.exists() ) { 31 | FileUtils.forceDelete( file ); 32 | } else { 33 | log.debug( "File '{}' has already been deleted.", file ); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/util/NamedBufferedInputStream.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileNotFoundException; 7 | import java.io.InputStream; 8 | 9 | public class NamedBufferedInputStream extends BufferedInputStream { 10 | 11 | private final String name; 12 | 13 | public NamedBufferedInputStream( final InputStream in, final String name ) { 14 | super( in ); 15 | this.name = name; 16 | } 17 | 18 | public NamedBufferedInputStream( final File file ) throws FileNotFoundException { 19 | super( new FileInputStream( file ) ); 20 | name = file.getAbsolutePath(); 21 | } 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return getClass().getName() + "[" + name + "]"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/util/OptionalUtil.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import java.util.Optional; 4 | import java.util.function.Supplier; 5 | import java.util.stream.Stream; 6 | 7 | public class OptionalUtil { 8 | 9 | private OptionalUtil() {} 10 | 11 | @SuppressWarnings( "unchecked" ) 12 | public static Stream stream( final Optional o ) { 13 | return (Stream) o.map( Stream::of ).orElseGet( Stream::empty ); 14 | } 15 | 16 | @SuppressWarnings( "unchecked" ) 17 | public static Optional or( final Optional o, 18 | final Supplier> s ) { 19 | return (Optional) (o.isPresent() ? o : s.get()); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/retest/recheck/util/Predicates.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import java.util.function.Predicate; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | @Slf4j 8 | public final class Predicates { 9 | private Predicates() {} 10 | 11 | public static Predicate catchExceptionAsFalse( final Predicate unCatchedPredicate ) { 12 | return argument -> { 13 | try { 14 | return unCatchedPredicate.test( argument ); 15 | } catch ( final Exception willBeIgnored ) { 16 | log.info( "Return false for ignored {}:", willBeIgnored.getClass(), willBeIgnored.getMessage() ); 17 | return false; 18 | } 19 | }; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/default-recheck.ignore: -------------------------------------------------------------------------------- 1 | # Ignore file for recheck. Please do not delete, even if it is empty. 2 | 3 | # You can ignore specific elements like so (includes children): 4 | # matcher: type=meta 5 | 6 | # Or via absolute XPath: 7 | # matcher: xpath=html[1]/body[1]/iframe[1] 8 | 9 | # Or if you want to ignore everything, except specific dom-subtrees: 10 | # matcher: type=html, exclude(matcher: xpath=html/body/section[4]) 11 | 12 | # To ignore attributes globally, use: 13 | # attribute=class 14 | 15 | # To ignore attributes for a subtree of the DOM, use: 16 | # matcher: id=menu, attribute=text 17 | 18 | # You can also use regex for elements or attributes: 19 | # attribute-regex=data-.* 20 | 21 | # You can import other filters to quickly achieve what you want: 22 | # import: positioning.filter 23 | 24 | # More details and examples can be found here: 25 | # https://docs.retest.de/recheck/usage/filter/ 26 | 27 | # Ignore volatile metadata differences 28 | import: volatile-metadata.filter 29 | 30 | # These are sensible defaults, delete if they don't apply: 31 | attribute=style 32 | matcher: type=input, attribute-regex=border-.*-color 33 | pixel-diff=5px 34 | -------------------------------------------------------------------------------- /src/main/resources/default-recheck.ignore.js: -------------------------------------------------------------------------------- 1 | // Here you can implement ignore rules for recheck in JavaScript. 2 | // Please do not delete this file, even if it is empty. 3 | 4 | // You can implement either of these two functions: 5 | // function matches(element) {} 6 | // function matches(element, diff) {} 7 | 8 | // For example, to ignore everything behind an URL after '?': 9 | 10 | //var baseUrl = /http[s]?:\/\/[\w.:\d\-]*/; 11 | // 12 | //function matches(element, diff) { 13 | // if (diff.expected != null && diff.actual != null) { 14 | // expected = new String(diff.expected); 15 | // actual = new String(diff.actual); 16 | // cleanExpected = expected.replace(baseUrl, ''); 17 | // cleanActual = actual.replace(baseUrl, ''); 18 | // return cleanExpected === cleanActual; 19 | // } 20 | // return false; 21 | //} 22 | 23 | // You can find more details and example rules at: 24 | // https://docs.retest.de/recheck/how-ignore-works/ 25 | -------------------------------------------------------------------------------- /src/main/resources/default-retest.properties: -------------------------------------------------------------------------------- 1 | # Defaults for recheck. Please do not delete, even if this file is empty. 2 | 3 | # Upload test reports to rehub. 4 | # de.retest.recheck.rehub.reportUploadEnabled=false 5 | 6 | # Always ignore these (separate values with ;) attributes. 7 | de.retest.recheck.ignore.attributes=absolute-outline 8 | -------------------------------------------------------------------------------- /src/main/resources/filter/metadata.filter: -------------------------------------------------------------------------------- 1 | import: volatile-metadata.filter 2 | 3 | # for recheck-web 4 | attribute=browser.name 5 | attribute=browser.version 6 | attribute=check.type 7 | attribute=driver.type 8 | attribute=os.name 9 | attribute=os.version 10 | attribute=url -------------------------------------------------------------------------------- /src/main/resources/filter/volatile-metadata.filter: -------------------------------------------------------------------------------- 1 | # These differences should be recorded in the GM for diagnosing, 2 | # but are too verbose and too volatile 3 | # to be spilled out for every change 4 | 5 | attribute=machine.name 6 | attribute=os.arch 7 | attribute=vcs.branch 8 | attribute=vcs.commit 9 | attribute=vcs.name 10 | attribute=time.date 11 | attribute=time.time 12 | attribute=time.offset 13 | attribute=time.zone -------------------------------------------------------------------------------- /src/main/resources/filter/web/content.filter: -------------------------------------------------------------------------------- 1 | # Filter file for recheck that will filter content 2 | 3 | attribute=text 4 | attribute=title 5 | matcher: type=img, attribute: src 6 | matcher: type=img, attribute: alt 7 | matcher: type=input, attribute: placeholder 8 | 9 | # Ignore time 10 | matcher: type=time, attribute=datetime 11 | 12 | # Ignore svgs 13 | matcher: type=svg 14 | -------------------------------------------------------------------------------- /src/main/resources/filter/web/positioning.filter: -------------------------------------------------------------------------------- 1 | # Positioning filter file for recheck. 2 | 3 | # Ignore attributes that are concerned with positioning: 4 | 5 | attribute=top 6 | attribute=bottom 7 | attribute=right 8 | attribute=left 9 | 10 | attribute=width 11 | attribute=height 12 | attribute=min-width 13 | attribute=min-height 14 | attribute=max-width 15 | attribute=max-height 16 | 17 | attribute=vertical-align 18 | 19 | attribute=clip 20 | 21 | attribute=margin-top 22 | attribute=margin-right 23 | attribute=margin-bottom 24 | attribute=margin-left 25 | 26 | attribute=object-position 27 | attribute=outline 28 | attribute=absolute-outline 29 | attribute=position 30 | 31 | attribute=padding-top 32 | attribute=padding-right 33 | attribute=padding-bottom 34 | attribute=padding-left 35 | 36 | attribute=z-index 37 | 38 | matcher: type=br, change=inserted 39 | matcher: type=br, change=deleted 40 | -------------------------------------------------------------------------------- /src/main/resources/retest-defaults.properties: -------------------------------------------------------------------------------- 1 | de.retest.testresults.testreport.xsl=/de/retest/testreport.html.xsl 2 | de.retest.testresults.testreport.htmlAssets=/de/retest/css/default.css;/de/retest/css/layout.css;/de/retest/css/media-queries.css;/de/retest/css/prettify.css;/de/retest/img/apple-touch-icon.png;/de/retest/img/favicon.ico;/de/retest/img/go-to-top.png;/de/retest/img/feedback-tab.png;/de/retest/img/logo.png;/de/retest/js/modernizr.js;/de/retest/js/jquery-1.12.3.min.js;/de/retest/js/retest.js 3 | de.retest.testresults.testreport.excelAssets=/de/retest/excel/[Content_Types].xml;/de/retest/excel/_rels/.rels;/de/retest/excel/docProps/app.xml;/de/retest/excel/docProps/core.xml;/de/retest/excel/xl/_rels/workbook.xml.rels;/de/retest/excel/xl/drawings/_rels/vmlDrawing1.vml.rels;/de/retest/excel/xl/drawings/vmlDrawing1.vml;/de/retest/excel/xl/media/image1.png;/de/retest/excel/xl/sharedStrings.xml;/de/retest/excel/xl/styles.xml;/de/retest/excel/xl/theme/theme1.xml;/de/retest/excel/xl/workbook.xml;/de/retest/excel/xl/worksheets/_rels/sheet1.xml.rels 4 | de.retest.ui.ignoreWindows=javax.swing.SwingUtilities$SharedOwnerFrame 5 | de.retest.killAdditionalThreads=true 6 | de.retest.vmArgs=-Xms1g -server -Dsun.java2d.xrender=false -Dsun.java2d.d3d=false -XX:+UseParallelGC -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="${de.retest.workDirectory}" 7 | de.retest.version=${pom.parent.version} 8 | -------------------------------------------------------------------------------- /src/test/java/DefaultRecheckIgnoreJsTest.java: -------------------------------------------------------------------------------- 1 | import static org.assertj.core.api.Assertions.assertThat; 2 | 3 | import java.nio.file.Paths; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.RegisterExtension; 7 | import org.slf4j.event.Level; 8 | 9 | import de.retest.recheck.ignore.JSFilterImpl; 10 | import io.github.netmikey.logunit.api.LogCapturer; 11 | 12 | public class DefaultRecheckIgnoreJsTest { 13 | 14 | @RegisterExtension 15 | LogCapturer warningAndErrorLogs = LogCapturer.create() // 16 | .forLevel( Level.WARN ) // 17 | .captureForType( JSFilterImpl.class ); 18 | 19 | @Test 20 | void default_recheck_ignore_should_load_without_exception() throws Exception { 21 | new JSFilterImpl( Paths.get( getClass().getResource( "default-recheck.ignore.js" ).toURI() ) ); 22 | 23 | // Assert that no error was logged... 24 | assertThat( warningAndErrorLogs.size() ).isEqualTo( 0 ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/DefaultRecheckIgnoreTest.java: -------------------------------------------------------------------------------- 1 | import static de.retest.recheck.ignore.FilterLoader.load; 2 | import static java.nio.file.Paths.get; 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.RegisterExtension; 7 | 8 | import de.retest.recheck.review.ignore.io.ErrorHandlingLoader; 9 | import io.github.netmikey.logunit.api.LogCapturer; 10 | 11 | class DefaultRecheckIgnoreTest { 12 | 13 | @RegisterExtension 14 | LogCapturer warningAndErrorLogs = LogCapturer.create() // 15 | .captureForType( ErrorHandlingLoader.class ); 16 | 17 | @Test 18 | void default_recheck_ignore_should_load_without_exception() throws Exception { 19 | load( get( getClass().getResource( "default-recheck.ignore" ).toURI() ) ).load(); 20 | 21 | // Assert that no error was logged... 22 | assertThat( warningAndErrorLogs.size() ).isEqualTo( 0 ); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/FileNamerStrategyTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | import de.retest.recheck.persistence.FileNamer; 8 | 9 | @SuppressWarnings( "deprecation" ) 10 | class FileNamerStrategyTest { 11 | 12 | static class FileNamerStrategyImpl implements FileNamerStrategy { 13 | @Override 14 | public FileNamer createFileNamer( final String... baseNames ) { 15 | return null; 16 | } 17 | } 18 | 19 | @Test 20 | void default_test_class_name_should_be_implemented() throws Exception { 21 | final FileNamerStrategy cut = new FileNamerStrategyImpl(); 22 | assertThat( cut.getTestClassName() ).isEqualTo( getClass().getName() ); 23 | } 24 | 25 | @Test 26 | void default_test_method_name_should_be_implemented() throws Exception { 27 | final FileNamerStrategy cut = new FileNamerStrategyImpl(); 28 | assertThat( cut.getTestMethodName() ).isEqualTo( "default_test_method_name_should_be_implemented" ); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/MavenConformFileNamerStrategyTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.io.File; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import de.retest.recheck.persistence.FileNamer; 10 | 11 | class MavenConformFileNamerStrategyTest { 12 | 13 | @Test 14 | void files_should_be_maven_conform() throws Exception { 15 | final FileNamerStrategy cut = new MavenConformFileNamerStrategy(); 16 | 17 | final FileNamer fileNamer = cut.createFileNamer( "foo", "bar" ); 18 | final File goldenMaster = fileNamer.getFile( RecheckProperties.GOLDEN_MASTER_FILE_EXTENSION ); 19 | final File resultFile = fileNamer.getResultFile( RecheckProperties.TEST_REPORT_FILE_EXTENSION ); 20 | 21 | assertThat( goldenMaster.getPath() ).isEqualTo( "src/test/resources/retest/recheck/foo/bar.recheck" ); 22 | assertThat( resultFile.getPath() ).isEqualTo( "target/test-classes/retest/recheck/foo/bar.report" ); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/NoGoldenMasterActionReplayResultTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Answers.RETURNS_MOCKS; 5 | import static org.mockito.Mockito.mock; 6 | import static org.mockito.Mockito.when; 7 | 8 | import java.util.Collections; 9 | 10 | import org.junit.jupiter.api.Test; 11 | 12 | import de.retest.recheck.ui.descriptors.RootElement; 13 | import de.retest.recheck.ui.descriptors.SutState; 14 | 15 | class NoGoldenMasterActionReplayResultTest { 16 | 17 | @Test 18 | void hasDifference_should_always_return_true() { 19 | final RootElement rootElement = mock( RootElement.class, RETURNS_MOCKS ); 20 | 21 | final SutState sutState = mock( SutState.class ); 22 | when( sutState.getRootElements() ).thenReturn( Collections.singletonList( rootElement ) ); 23 | 24 | final NoGoldenMasterActionReplayResult cut = new NoGoldenMasterActionReplayResult( "result", sutState, "path" ); 25 | 26 | assertThat( cut.hasDifferences() ).isTrue(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/RecheckCapMessageTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck; 2 | 3 | import static org.mockito.Mockito.mock; 4 | import static org.mockito.Mockito.when; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import de.retest.recheck.report.ActionReplayResult; 9 | import de.retest.recheck.report.TestReplayResult; 10 | import de.retest.recheck.util.ApprovalsUtil; 11 | 12 | class RecheckCapMessageTest { 13 | 14 | @Test 15 | void no_golden_master_message_should_be_formatted_properly() throws Exception { 16 | final ActionReplayResult actionReplayResult0 = mock( NoGoldenMasterActionReplayResult.class ); 17 | when( actionReplayResult0.getGoldenMasterPath() ).thenReturn( "/gm/path/0" ); 18 | 19 | final ActionReplayResult actionReplayResult1 = mock( NoGoldenMasterActionReplayResult.class ); 20 | when( actionReplayResult1.getGoldenMasterPath() ).thenReturn( "/gm/path/0" ); 21 | 22 | final TestReplayResult testReplayResult = new TestReplayResult( "test-name", 1 ); 23 | testReplayResult.addAction( actionReplayResult0 ); 24 | testReplayResult.addAction( actionReplayResult1 ); 25 | 26 | final RecheckCapMessage cut = new RecheckCapMessage( "SomeSuite", testReplayResult, null, null ); 27 | 28 | ApprovalsUtil.verify( cut ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/auth/RetestAuthenticationTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.auth; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Disabled; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import de.retest.recheck.Rehub; 9 | 10 | public class RetestAuthenticationTest { 11 | 12 | @Test 13 | void getRequestParameters_should_be_valid() throws Exception { 14 | final String request = "GET " + "/?state=37a6d043-e49c-4aaa-a6e3-580c29a5f706&" 15 | + "session_state=3d025532-7ba4-4611-bb86-b51352605e74&" 16 | + "code=5b0893dd-32bb-4853-be3f-60f72ddf6635.3d025532-7ba4-4611-bb86-b51352605e74.ca0086b2-de26-4dfb-a5a0-b9588bbc77ac" 17 | + " HTTP/1.1"; 18 | 19 | final KeycloakResult sut = RetestAuthentication.getRequestParameters( request ); 20 | 21 | assertThat( sut.getState() ).isEqualTo( "37a6d043-e49c-4aaa-a6e3-580c29a5f706" ); 22 | assertThat( sut.getCode() ).isEqualTo( 23 | "5b0893dd-32bb-4853-be3f-60f72ddf6635.3d025532-7ba4-4611-bb86-b51352605e74.ca0086b2-de26-4dfb-a5a0-b9588bbc77ac" ); 24 | assertThat( sut.getError() ).isNull(); 25 | assertThat( sut.getErrorDescription() ).isNull(); 26 | assertThat( sut.getErrorException() ).isNull(); 27 | } 28 | 29 | @Test 30 | @Disabled( "manual test" ) 31 | void getRecheckApiKey_should_work() throws Exception { 32 | Rehub.init(); 33 | Rehub.authenticate(); 34 | Rehub.getRecheckApiKey(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/configuration/ProjectConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.configuration; 2 | 3 | import static de.retest.recheck.configuration.ProjectRootFinderUtil.getProjectRoot; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import java.nio.file.Path; 7 | 8 | import org.junit.jupiter.api.Test; 9 | 10 | import de.retest.recheck.RecheckProperties; 11 | 12 | class ProjectConfigurationTest { 13 | 14 | ProjectConfiguration cut = ProjectConfiguration.getInstance(); 15 | 16 | @Test 17 | void local_config_file_should_be_created() throws Exception { 18 | cut.ensureProjectConfigurationInitialized(); 19 | 20 | final Path configFolder = getProjectRoot().get().resolve( RecheckProperties.RETEST_FOLDER_NAME ); 21 | final Path configFile = configFolder.resolve( ProjectConfiguration.RETEST_PROJECT_PROPERTIES ); 22 | final Path ignpreFile = configFolder.resolve( ProjectConfiguration.RECHECK_IGNORE ); 23 | 24 | assertThat( configFolder ).exists(); 25 | assertThat( configFolder ).isDirectory(); 26 | assertThat( configFile ).exists(); 27 | assertThat( configFile ).isRegularFile(); 28 | assertThat( ignpreFile ).exists(); 29 | assertThat( ignpreFile ).isRegularFile(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/execution/RecheckAdaptersTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.execution; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import de.retest.recheck.RecheckOptions; 9 | 10 | class RecheckAdaptersTest { 11 | 12 | @Test 13 | void findAdapterFor_should_throw_exception_if_none_found() { 14 | assertThatThrownBy( () -> RecheckAdapters.findAdapterFor( new Object(), RecheckOptions.builder().build() ) ) // 15 | .isInstanceOf( UnsupportedOperationException.class ) // 16 | .hasMessage( "No recheck adapter registered that can handle an object of class java.lang.Object." ); 17 | } 18 | 19 | @Test 20 | void findAdapterFor_should_throw_helpful_message_for_common_errors() { 21 | assertThat( RecheckAdapters.createHelpfulExceptionForMissingAdapter( "org.openqa.selenium.chrome.ChromeDriver" ) 22 | .getMessage() ).isEqualTo( 23 | "No recheck adapter registered that can handle an object of class org.openqa.selenium.chrome.ChromeDriver.\n " 24 | + "You need to add recheck-web (https://github.com/retest/recheck-web) to the classpath." ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ignore/FilterLoaderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 5 | 6 | import java.nio.file.NoSuchFileException; 7 | import java.nio.file.Paths; 8 | 9 | import org.junit.jupiter.api.Test; 10 | 11 | import de.retest.recheck.ui.descriptors.Element; 12 | 13 | class FilterLoaderTest { 14 | 15 | @Test 16 | void loading_filterjs_should_load_JavaScript() throws Exception { 17 | final FilterLoader loader = 18 | FilterLoader.load( Paths.get( getClass().getResource( "file.filter.js" ).toURI() ) ); 19 | final Filter filter = loader.load(); 20 | assertThat( filter ).isInstanceOf( JSFilterImpl.class ); 21 | final Element element = null; 22 | final String attributeKey = null; 23 | assertThat( filter.matches( element, attributeKey ) ).isTrue(); 24 | } 25 | 26 | @Test 27 | void loadResource_should_properly_throw_descriptive_exception_if_resource_not_present() { 28 | final FilterLoader cut = FilterLoader.loadResource( "/not-present-file.file" ); 29 | 30 | assertThatThrownBy( cut::load ).isInstanceOf( NoSuchFileException.class ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ignore/GloballyIgnoredAttributesTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Collections; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | class GloballyIgnoredAttributesTest { 10 | 11 | @Test 12 | public void only_ignored_attribute_should_be_ignored() throws Exception { 13 | try { 14 | final GloballyIgnoredAttributes ignored = 15 | GloballyIgnoredAttributes.getTestInstance( Collections.singletonList( "text" ) ); 16 | assertThat( ignored.shouldIgnoreAttribute( "text" ) ).isTrue(); 17 | assertThat( ignored.shouldIgnoreAttribute( "color" ) ).isFalse(); 18 | } finally { 19 | GloballyIgnoredAttributes.resetTestInstance(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ignore/SearchFilterFilesIT.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThatCode; 4 | 5 | import org.apache.commons.lang3.tuple.Pair; 6 | import org.junit.jupiter.api.Nested; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import de.retest.recheck.ignore.SearchFilterFiles.FilterResource; 10 | 11 | class SearchFilterFilesIT { 12 | 13 | @Nested 14 | class FilterResourceIT { 15 | 16 | @Test 17 | void loader_should_properly_load_resource() { 18 | final FilterResource cut = FilterResource.prefix( "web", "content.filter" ); 19 | 20 | final Pair pair = cut.loader(); 21 | final FilterLoader loader = pair.getRight(); 22 | 23 | assertThatCode( loader::load ).doesNotThrowAnyException(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/meta/GlobalMetadataProviderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta; 2 | 3 | import static org.assertj.core.api.Assertions.assertThatCode; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | class GlobalMetadataProviderTest { 8 | 9 | @Test 10 | void retrieve_should_not_throw_an_exception() throws Exception { 11 | final MetadataProvider cut = new GlobalMetadataProvider(); 12 | 13 | assertThatCode( cut::retrieve ).doesNotThrowAnyException(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/meta/MetadataProviderServiceTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | import static org.mockito.Mockito.when; 6 | 7 | import java.util.Collections; 8 | 9 | import org.apache.commons.lang3.tuple.Pair; 10 | import org.junit.jupiter.api.Test; 11 | 12 | class MetadataProviderServiceTest { 13 | 14 | @Test 15 | void retrieve_should_allow_for_duplicate_keys_and_should_always_prefer_local_over_global() throws Exception { 16 | final MetadataProvider global = mock( MetadataProvider.class ); 17 | when( global.retrieve() ).thenReturn( Collections.singletonMap( "a", "b" ) ); 18 | 19 | final MetadataProvider local = mock( MetadataProvider.class ); 20 | when( local.retrieve() ).thenReturn( Collections.singletonMap( "a", "c" ) ); 21 | 22 | final MetadataProviderService cut = new MetadataProviderService( global, local ); 23 | 24 | assertThat( cut.retrieve() ) // 25 | .hasSize( 1 ) // 26 | .contains( Pair.of( "a", "c" ) ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/meta/global/OSMetadataProviderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta.global; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Map; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import de.retest.recheck.meta.MetadataProvider; 10 | 11 | class OSMetadataProviderTest { 12 | 13 | @Test 14 | void retrieve_should_capture_all_required_metadata() throws Exception { 15 | final MetadataProvider cut = new OSMetadataProvider(); 16 | 17 | final Map metadata = cut.retrieve(); 18 | 19 | assertThat( metadata ).hasSize( 3 ); 20 | assertThat( metadata ).containsKey( OSMetadataProvider.OS_ARCH ); 21 | assertThat( metadata ).containsKey( OSMetadataProvider.OS_NAME ); 22 | assertThat( metadata ).containsKey( OSMetadataProvider.OS_VERSION ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/meta/global/TimeMetadataProviderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.meta.global; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Map; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import de.retest.recheck.meta.MetadataProvider; 10 | 11 | class TimeMetadataProviderTest { 12 | 13 | @Test 14 | void retrieve_should_capture_all_required_metadata() throws Exception { 15 | final MetadataProvider cut = new TimeMetadataProvider(); 16 | 17 | final Map metadata = cut.retrieve(); 18 | 19 | assertThat( metadata ).hasSize( 4 ); 20 | assertThat( metadata ).containsKey( TimeMetadataProvider.TIME ); 21 | assertThat( metadata ).containsKey( TimeMetadataProvider.DATE ); 22 | assertThat( metadata ).containsKey( TimeMetadataProvider.OFFSET ); 23 | assertThat( metadata ).containsKey( TimeMetadataProvider.ZONE ); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/ClassAndMethodBasedNamingStrategyTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | class ClassAndMethodBasedNamingStrategyTest { 8 | 9 | @Test 10 | void getSuiteName_should_return_qualified_test_class_name() throws Exception { 11 | final NamingStrategy cut = new ClassAndMethodBasedNamingStrategy(); 12 | assertThat( cut.getSuiteName() ).isEqualTo( getClass().getName() ); 13 | } 14 | 15 | @Test 16 | void getTestName_should_return_test_method_name() throws Exception { 17 | final NamingStrategy cut = new ClassAndMethodBasedNamingStrategy(); 18 | assertThat( cut.getTestName() ).isEqualTo( "getTestName_should_return_test_method_name" ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/ClassAndMethodBasedShortNamingStrategyTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | class ClassAndMethodBasedShortNamingStrategyTest { 8 | 9 | static class InnerClass { 10 | @Test 11 | void getSuiteName_should_return_test_class_simple_name() throws Exception { 12 | final NamingStrategy cut = new ClassAndMethodBasedShortNamingStrategy(); 13 | assertThat( cut.getSuiteName() ) 14 | .isEqualTo( ClassAndMethodBasedShortNamingStrategyTest.class.getSimpleName() ); 15 | } 16 | } 17 | 18 | @Test 19 | void getSuiteName_should_return_test_class_simple_name() throws Exception { 20 | final NamingStrategy cut = new ClassAndMethodBasedShortNamingStrategy(); 21 | assertThat( cut.getSuiteName() ).isEqualTo( getClass().getSimpleName() ); 22 | } 23 | 24 | @Test 25 | void getTestName_should_return_test_method_name() throws Exception { 26 | final NamingStrategy cut = new ClassAndMethodBasedShortNamingStrategy(); 27 | assertThat( cut.getTestName() ).isEqualTo( "getTestName_should_return_test_method_name" ); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/MavenConformFileNamerTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.nio.file.Path; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | class MavenConformFileNamerTest { 10 | 11 | @Test 12 | void files_should_be_maven_conform() throws Exception { 13 | final MavenProjectLayout layout = new MavenProjectLayout(); 14 | final Path goldenMaster = layout.getGoldenMaster( "foo", "", "bar" ); 15 | final Path resultFile = layout.getReport( "bar" ); 16 | 17 | assertThat( goldenMaster.toString() ).isEqualTo( "src/test/resources/retest/recheck/foo/bar.recheck" ); 18 | assertThat( resultFile.toString() ).isEqualTo( "target/test-classes/retest/recheck/bar.report" ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/MavenProjectLayoutTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.nio.file.Paths; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | class MavenProjectLayoutTest { 10 | 11 | @Test 12 | void getTestResourceRoot_for_main_should_return_correct_path() throws Exception { 13 | final ProjectLayout cut = new MavenProjectLayout(); 14 | 15 | assertThat( cut.getTestSourcesRoot() ).hasValue( Paths.get( "src/test/java" ) ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/NoGoldenMasterFoundExceptionTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | class NoGoldenMasterFoundExceptionTest { 9 | 10 | @Test 11 | void should_fail_if_no_files_provided() throws Exception { 12 | assertThatThrownBy( NoGoldenMasterFoundException::new ) // 13 | .isInstanceOf( IllegalArgumentException.class ) 14 | .hasMessage( "You should at least provide one Golden Master file." ); 15 | } 16 | 17 | @Test 18 | void should_format_single_golden_master_accordingly() throws Exception { 19 | final NoGoldenMasterFoundException cut = new NoGoldenMasterFoundException( "foo" ); 20 | 21 | assertThat( cut ).hasMessage( "The following Golden Master(s) cannot be found:\n" // 22 | + "\t- foo" ); 23 | } 24 | 25 | @Test 26 | void should_format_multiple_golden_masters_accordingly() throws Exception { 27 | final NoGoldenMasterFoundException cut = new NoGoldenMasterFoundException( "foo", "bar" ); 28 | 29 | assertThat( cut ).hasMessage( "The following Golden Master(s) cannot be found:\n" // 30 | + "\t- foo\n" // 31 | + "\t- bar" ); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/migration/transformers/AddRetestIdTestTransformerIT.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.migration.transformers; 2 | 3 | import static com.google.common.base.Charsets.UTF_8; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.InputStream; 8 | 9 | import org.apache.commons.io.IOUtils; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import de.retest.recheck.persistence.migration.XmlTransformer; 13 | import de.retest.recheck.persistence.migration.transformers.AddRetestIdTestTransformer.RetestIdCreator; 14 | import de.retest.recheck.util.ApprovalsUtil; 15 | 16 | class AddRetestIdTestTransformerIT { 17 | 18 | @Test 19 | void retestId_should_be_added() throws Exception { 20 | final InputStream inputStream = 21 | new FileInputStream( new File( "src/test/resources/migration/AddRetestIdTestTransformer.xml" ) ); 22 | 23 | final XmlTransformer transformer = new AddRetestIdTestTransformer( new RetestIdCreator() { 24 | private int counter = 0; 25 | 26 | @Override 27 | public String retestId() { 28 | return Integer.toString( counter++ ); 29 | } 30 | } ); 31 | final InputStream transform = transformer.transform( inputStream ); 32 | ApprovalsUtil.verifyXml( IOUtils.toString( transform, UTF_8.name() ) ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/migration/transformers/PathAndType2LowerCaseTransformerIT.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.migration.transformers; 2 | 3 | import static com.google.common.base.Charsets.UTF_8; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.InputStream; 8 | 9 | import org.apache.commons.io.IOUtils; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import de.retest.recheck.persistence.migration.XmlTransformer; 13 | import de.retest.recheck.util.ApprovalsUtil; 14 | 15 | class PathAndType2LowerCaseTransformerIT { 16 | 17 | @Test 18 | void path_should_be_transformed() throws Exception { 19 | final InputStream inputStream = 20 | new FileInputStream( new File( "src/test/resources/migration/PathAndType2LowerCaseTransformer.xml" ) ); 21 | 22 | final XmlTransformer transformer = new PathAndType2LowerCaseTransformer(); 23 | final InputStream transform = transformer.transform( inputStream ); 24 | ApprovalsUtil.verifyXml( IOUtils.toString( transform, UTF_8.name() ) ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/migration/transformers/WindowSuffixTransformerIT.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.migration.transformers; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.InputStream; 6 | 7 | import org.apache.commons.io.IOUtils; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import de.retest.recheck.util.ApprovalsUtil; 11 | 12 | class WindowSuffixTransformerIT { 13 | 14 | @Test 15 | void transform_should_replace_window_with_suffixed_window() throws Exception { 16 | final InputStream inputStream = 17 | new FileInputStream( new File( "src/test/resources/migration/WindowSuffixTransformerTest.xml" ) ); 18 | 19 | final WindowSuffixTransformer cut = new WindowSuffixTransformer(); 20 | 21 | final InputStream transform = cut.transform( inputStream ); 22 | 23 | ApprovalsUtil.verifyXml( IOUtils.toString( transform, "UTF-8" ) ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/xml/TestPersistable.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.xml; 2 | 3 | import de.retest.recheck.persistence.Persistable; 4 | 5 | public class TestPersistable extends Persistable { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | public static final String CLASS_NAME = TestPersistable.class.getName(); 10 | public static final int PERSISTENCE_VERSION = 9001; 11 | 12 | public static final String XML = generateXmlWith( CLASS_NAME, PERSISTENCE_VERSION ); 13 | 14 | public static final String XML_WITH_WRONG_VERSION = generateXmlWith( CLASS_NAME, PERSISTENCE_VERSION - 1 ); 15 | public static final String XML_WITH_RENAMED_CLASS = 16 | generateXmlWith( "de.retest.persistence.xml.ClassWithOldName", PERSISTENCE_VERSION - 1 ); 17 | 18 | private static String generateXmlWith( final String className, final int persistenceVersion ) { 19 | return "" + "" 22 | + "..."; 23 | } 24 | 25 | public TestPersistable() { 26 | super( PERSISTENCE_VERSION ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/persistence/xml/util/ScreenshotTransformerTestJaxbClass.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.persistence.xml.util; 2 | 3 | import de.retest.recheck.persistence.Persistable; 4 | import de.retest.recheck.ui.image.Screenshot; 5 | import jakarta.xml.bind.annotation.XmlAccessType; 6 | import jakarta.xml.bind.annotation.XmlAccessorType; 7 | import jakarta.xml.bind.annotation.XmlElement; 8 | import jakarta.xml.bind.annotation.XmlRootElement; 9 | 10 | @XmlRootElement 11 | @XmlAccessorType( XmlAccessType.FIELD ) 12 | public class ScreenshotTransformerTestJaxbClass extends Persistable { 13 | 14 | private static final long serialVersionUID = 1L; 15 | private static final int PERSISTENCE_VERSION = 2; 16 | 17 | @XmlElement 18 | private Screenshot screenshot; 19 | 20 | public ScreenshotTransformerTestJaxbClass() { 21 | super( PERSISTENCE_VERSION ); 22 | } 23 | 24 | public Screenshot getScreenshot() { 25 | return screenshot; 26 | } 27 | 28 | public void setScreenshot( final Screenshot screenshot ) { 29 | this.screenshot = screenshot; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/printer/MetadataDifferencePrinterTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.printer; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | 8 | import org.junit.jupiter.api.Test; 9 | 10 | import de.retest.recheck.ui.diff.meta.MetadataDifference; 11 | import de.retest.recheck.ui.diff.meta.MetadataElementDifference; 12 | 13 | class MetadataDifferencePrinterTest { 14 | 15 | @Test 16 | void toString_should_properly_format_differences() throws Exception { 17 | final MetadataDifference differences = MetadataDifference.of( new HashSet<>( Arrays.asList( // 18 | new MetadataElementDifference( "a", "b", "c" ), // 19 | new MetadataElementDifference( "b", "c", "d" ) // 20 | ) ) ); 21 | 22 | final MetadataDifferencePrinter cut = new MetadataDifferencePrinter(); 23 | 24 | assertThat( cut.toString( differences, "____" ) ).isEqualTo( "____Metadata Differences:\n" // 25 | + "____ Please note that these differences do not affect the result and are not included " // 26 | + "in the difference count.\n" // 27 | + "____\ta: expected=\"b\", actual=\"c\"\n" // 28 | + "____\tb: expected=\"c\", actual=\"d\"" ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/review/ignore/AttributeFilterLoaderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | import de.retest.recheck.ignore.AllMatchFilter; 8 | import de.retest.recheck.ignore.Filter; 9 | import de.retest.recheck.review.ignore.AttributeFilter.AttributeFilterLoader; 10 | 11 | class AttributeFilterLoaderTest { 12 | 13 | final AttributeFilterLoader cut = new AttributeFilterLoader(); 14 | 15 | @Test 16 | void save_should_produce_same_as_was_given_to_load_for_simple_line() { 17 | final String line = "attribute=text"; 18 | assertThat( cut.load( line ) ).map( filter -> cut.save( filter ) ).hasValue( line ); 19 | } 20 | 21 | @Test 22 | void save_should_produce_same_as_was_given_to_load_for_chained_filter() { 23 | final String line = "attribute=outline, pixel-diff=5px"; 24 | assertThat( cut.load( line ).map( filter -> cut.save( filter ) ).get() ).isEqualTo( line ); 25 | } 26 | 27 | @Test 28 | void chained_filters_should_load_correctly() { 29 | final Filter loaded = cut.load( "attribute=outline, pixel-diff=5px" ).get(); 30 | assertThat( loaded ).isInstanceOf( AllMatchFilter.class ); 31 | assertThat( ((AllMatchFilter) loaded).getFilters() ).hasSize( 2 ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/review/ignore/AttributeRegexFilterLoaderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | import de.retest.recheck.ignore.AllMatchFilter; 8 | import de.retest.recheck.ignore.Filter; 9 | import de.retest.recheck.review.ignore.AttributeRegexFilter.AttributeRegexFilterLoader; 10 | 11 | class AttributeRegexFilterLoaderTest { 12 | 13 | final AttributeRegexFilterLoader cut = new AttributeRegexFilterLoader(); 14 | 15 | @Test 16 | void save_should_produce_same_as_was_given_to_load_for_simple_line() { 17 | final String line = "attribute-regex=my-.*-attribute"; 18 | assertThat( cut.load( line ).map( filter -> cut.save( filter ) ).get() ).isEqualTo( line ); 19 | } 20 | 21 | @Test 22 | void save_should_produce_same_as_was_given_to_load_for_chained_filter() { 23 | final String line = "attribute-regex=my-.*-attribute, pixel-diff=5px"; 24 | assertThat( cut.load( line ).map( filter -> cut.save( filter ) ).get() ).isEqualTo( line ); 25 | } 26 | 27 | @Test 28 | void chained_filters_should_load_correctly() { 29 | final Filter loaded = cut.load( "attribute-regex=my-.*-attribute, pixel-diff=5px" ).get(); 30 | assertThat( loaded ).isInstanceOf( AllMatchFilter.class ); 31 | assertThat( ((AllMatchFilter) loaded).getFilters() ).hasSize( 2 ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/review/ignore/AttributeRegexFilterTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import de.retest.recheck.ignore.Filter; 9 | import de.retest.recheck.ui.descriptors.Element; 10 | 11 | class AttributeRegexFilterTest { 12 | 13 | @Test 14 | void should_filter_if_regex_matches() { 15 | final Filter cut = new AttributeRegexFilter( "my-.*-key" ); 16 | assertThat( cut.matches( mock( Element.class ), "my-somewhatspecial-key" ) ).isTrue(); 17 | } 18 | 19 | @Test 20 | void should_not_filter_if_regex_doesnt_match() { 21 | final Filter cut = new AttributeRegexFilter( "my-.*-key" ); 22 | assertThat( cut.matches( mock( Element.class ), "my-otherattribute" ) ).isFalse(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/review/ignore/ExcludeFilterIT.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import de.retest.recheck.ui.descriptors.Element; 9 | import de.retest.recheck.ui.diff.AttributeDifference; 10 | 11 | class ExcludeFilterIT { 12 | 13 | @Test 14 | void load_should_handle_multiple_entries() { 15 | final Element element = mock( Element.class ); 16 | 17 | final AttributeFilter.AttributeFilterLoader delegate = new AttributeFilter.AttributeFilterLoader(); 18 | final ExcludeFilter.FilterLoader cut = new ExcludeFilter.FilterLoader( delegate ); 19 | 20 | assertThat( cut.load( "exclude(attribute=text), exclude(attribute=font)" ) ).hasValueSatisfying( filter -> { 21 | assertThat( filter.matches( element, "class" ) ).isTrue(); 22 | assertThat( filter.matches( element, difference( "class" ) ) ).isTrue(); 23 | 24 | assertThat( filter.matches( element, "font" ) ).isFalse(); 25 | assertThat( filter.matches( element, difference( "font" ) ) ).isFalse(); 26 | 27 | assertThat( filter.matches( element, "text" ) ).isFalse(); 28 | assertThat( filter.matches( element, difference( "text" ) ) ).isFalse(); 29 | } ); 30 | } 31 | 32 | private AttributeDifference difference( final String key ) { 33 | return new AttributeDifference( key, "expected", "actual" ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/review/ignore/RegexAttributeFilterTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | import static org.mockito.Mockito.when; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import de.retest.recheck.ui.descriptors.Attributes; 10 | import de.retest.recheck.ui.descriptors.Element; 11 | import de.retest.recheck.ui.diff.AttributeDifference; 12 | 13 | class RegexAttributeFilterTest { 14 | 15 | @Test 16 | void should_match_wildcard_attribute() { 17 | final AttributeRegexFilter filter = new AttributeRegexFilter( ".*Special.*" ); 18 | 19 | final Element element = mock( Element.class ); 20 | final Attributes attribs = mock( Attributes.class ); 21 | when( element.getAttributes() ).thenReturn( attribs ); 22 | when( attribs.get( "mySpecialAttribute" ) ).thenReturn( "someValue" ); 23 | 24 | final AttributeDifference attributeDifference = mock( AttributeDifference.class ); 25 | when( attributeDifference.getKey() ).thenReturn( "mySpecialAttribute" ); 26 | 27 | assertThat( filter.matches( element, attributeDifference ) ).isTrue(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/review/ignore/matcher/ElementRetestIdMatcherLoaderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.review.ignore.matcher; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | import static org.mockito.Mockito.when; 6 | 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import de.retest.recheck.review.ignore.matcher.ElementRetestIdMatcher.ElementRetestIdMatcherLoader; 11 | import de.retest.recheck.ui.descriptors.Element; 12 | 13 | class ElementRetestIdMatcherLoaderTest { 14 | 15 | ElementRetestIdMatcher matcher; 16 | ElementRetestIdMatcherLoader cut; 17 | 18 | @BeforeEach 19 | void setUp() { 20 | cut = new ElementRetestIdMatcherLoader(); 21 | 22 | final Element element = mock( Element.class ); 23 | when( element.getRetestId() ).thenReturn( "abc" ); 24 | matcher = new ElementRetestIdMatcher( element ); 25 | } 26 | 27 | @Test 28 | void save_should_produce_correct_line() { 29 | assertThat( cut.save( matcher ) ).isEqualTo( "retestid=abc" ); 30 | } 31 | 32 | @Test 33 | void load_should_produce_correct_ignore() { 34 | final String line = "retestid=abc"; 35 | assertThat( cut.load( line ).map( cut::save ) ).hasValue( line ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/actions/TargetNotFoundExceptionTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.actions; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | 6 | import org.junit.Test; 7 | import org.mockito.Mockito; 8 | 9 | import de.retest.recheck.ui.descriptors.Element; 10 | 11 | public class TargetNotFoundExceptionTest { 12 | 13 | @Test 14 | public void getMissingTarget_returns_the_target_invocation_descriptor() { 15 | final Action action = mock( Action.class ); 16 | final Element result = mock( Element.class ); 17 | Mockito.when( action.getTargetElement() ).thenReturn( result ); 18 | assertThat( new TargetNotFoundException( action, null, null, null ).getMissingTarget() ).isSameAs( result ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/ActionChangeSetTestUtils.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import de.retest.recheck.ui.review.ActionChangeSet; 4 | import de.retest.recheck.ui.review.ScreenshotChanges; 5 | 6 | public final class ActionChangeSetTestUtils { 7 | 8 | private ActionChangeSetTestUtils() {} 9 | 10 | static ActionChangeSet createEmptyActionChangeSet() { 11 | return new ActionChangeSet( null, null, ScreenshotChanges.empty() ); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/DefaultAttributeTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import static de.retest.recheck.ui.descriptors.DefaultAttribute.parameterTypeAttribute; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import org.junit.Test; 7 | 8 | public class DefaultAttributeTest { 9 | 10 | @Test 11 | public void parse_is_not_supported_and_should_return_null() throws Exception { 12 | assertThat( parameterTypeAttribute.parse( "value" ) ).isNull(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/PathAttributeTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import static de.retest.recheck.ui.descriptors.PathAttribute.parameterTypePath; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import org.junit.Test; 7 | 8 | import de.retest.recheck.ui.Path; 9 | import de.retest.recheck.ui.PathElement; 10 | 11 | public class PathAttributeTest { 12 | 13 | @Test 14 | public void parse_should_parse_path_correctly() throws Exception { 15 | final Path parent = Path.path( new PathElement( "parent" ) ); 16 | final Path path = Path.path( parent, new PathElement( "path" ) ); 17 | final Path test = Path.path( path, new PathElement( "test" ) ); 18 | 19 | assertThat( parameterTypePath.parse( "parent/path/test" ) ).isEqualTo( test ); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/RenderContainedElementsAdapterTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | 6 | import org.junit.Test; 7 | 8 | import de.retest.recheck.ui.Path; 9 | 10 | public class RenderContainedElementsAdapterTest { 11 | 12 | @Test 13 | public void element_should_exist_exactly_once_when_unmarshalling() throws Exception { 14 | final RenderContainedElementsAdapter cut = new RenderContainedElementsAdapter(); 15 | final Element e0 = cut.unmarshal( createNewElement() ); 16 | final Element e1 = cut.unmarshal( createNewElement() ); 17 | 18 | assertThat( cut.unmarshal( createNewElement() ) ).isSameAs( e0 ); 19 | assertThat( cut.unmarshal( createNewElement() ) ).isSameAs( e1 ); 20 | } 21 | 22 | private Element createNewElement() { 23 | return Element.create( 24 | "id", mock( Element.class ), IdentifyingAttributes 25 | .create( Path.fromString( "Window[0]/path[0]/Component[0]" ), java.awt.Component.class ), 26 | new Attributes() ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/SutStateTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Collections; 6 | import java.util.HashMap; 7 | 8 | import org.junit.jupiter.api.Test; 9 | 10 | import de.retest.recheck.ui.review.ActionChangeSet; 11 | 12 | class SutStateTest { 13 | 14 | @Test 15 | void applyChanges_should_change_metadata() { 16 | final HashMap oldMetadata = new HashMap<>(); 17 | oldMetadata.put( "unchanged", "oldValue" ); 18 | oldMetadata.put( "updated", "oldValue" ); 19 | final SutState old = new SutState( Collections.emptyList(), () -> oldMetadata ); 20 | 21 | final HashMap newMetadata = new HashMap<>(); 22 | newMetadata.put( "updated", "newValue" ); 23 | final ActionChangeSet update = new ActionChangeSet( "update", "", null, newMetadata ); 24 | 25 | final SutState updated = old.applyChanges( update ); 26 | 27 | assertThat( updated.getMetadata( "unchanged" ) ).isEqualTo( "oldValue" ); 28 | assertThat( updated.getMetadata( "updated" ) ).isEqualTo( "newValue" ); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/TextAttributeTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | class TextAttributeTest { 8 | 9 | @Test 10 | void should_not_trim_the_value() { 11 | final String text = " foo "; 12 | final TextAttribute cut = new TextAttribute( "text", text ); 13 | assertThat( cut.getValue() ).isEqualTo( text ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/VariableNameAttributeDifferenceTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.Test; 6 | 7 | public class VariableNameAttributeDifferenceTest { 8 | 9 | @Test 10 | public void applyChangeTo_should_change_variable() { 11 | final ParameterizedAttribute attribute = new DefaultAttribute( "key", "value" ); 12 | final VariableNameAttributeDifference difference = new VariableNameAttributeDifference( attribute, "variable" ); 13 | 14 | final Attribute changed = difference.applyChangeTo( attribute ); 15 | 16 | assertThat( attribute.getVariableName() ).isEqualTo( null ); 17 | assertThat( changed ).isInstanceOf( ParameterizedAttribute.class ); 18 | assertThat( ((ParameterizedAttribute) changed).getVariableName() ).isEqualTo( "variable" ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/descriptors/idproviders/ElementCountingRetestIdProviderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.descriptors.idproviders; 2 | 3 | import static de.retest.recheck.ui.Path.fromString; 4 | import static de.retest.recheck.ui.descriptors.IdentifyingAttributes.create; 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | class ElementCountingRetestIdProviderTest { 10 | 11 | @Test 12 | void test() { 13 | final ElementCountingRetestIdProvider cut = new ElementCountingRetestIdProvider(); 14 | assertThat( cut.getRetestId( create( fromString( "/html[1]/div[1]" ), "div" ) ) ).isEqualTo( "div" ); 15 | assertThat( cut.getRetestId( create( fromString( "/html[1]/div[1]/div[1]" ), "div" ) ) ).isEqualTo( "div-1" ); 16 | assertThat( cut.getRetestId( create( fromString( "/html[1]/div[4]" ), "div" ) ) ).isEqualTo( "div-2" ); 17 | assertThat( cut.getRetestId( create( fromString( "/html[1]/a[1]" ), "a" ) ) ).isEqualTo( "a" ); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/diff/ElementDifferenceAdapter.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.diff; 2 | 3 | import static de.retest.recheck.ui.diff.ElementDifference.getCopyWithFlattenedChildDifferenceHierarchy; 4 | 5 | import jakarta.xml.bind.annotation.adapters.XmlAdapter; 6 | 7 | public class ElementDifferenceAdapter extends XmlAdapter { 8 | 9 | private final boolean renderLightweightXml; 10 | 11 | public ElementDifferenceAdapter() { 12 | renderLightweightXml = false; 13 | } 14 | 15 | public ElementDifferenceAdapter( final boolean renderLightweightXml ) { 16 | this.renderLightweightXml = renderLightweightXml; 17 | } 18 | 19 | @Override 20 | public ElementDifference marshal( final ElementDifference difference ) throws Exception { 21 | return renderLightweightXml ? getCopyWithFlattenedChildDifferenceHierarchy( difference ) : difference; 22 | } 23 | 24 | @Override 25 | public ElementDifference unmarshal( final ElementDifference difference ) throws Exception { 26 | return difference; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/diff/InsertedDeletedElementDifferenceTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.diff; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Mockito.mock; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import de.retest.recheck.ui.descriptors.Element; 9 | 10 | class InsertedDeletedElementDifferenceTest { 11 | 12 | @Test 13 | void should_return_correct_element() { 14 | final Element element = mock( Element.class ); 15 | final InsertedDeletedElementDifference inserted = 16 | InsertedDeletedElementDifference.differenceFor( null, element ); 17 | final InsertedDeletedElementDifference deleted = 18 | InsertedDeletedElementDifference.differenceFor( element, null ); 19 | assertThat( inserted.getInsertedOrDeletedElement() ).isEqualTo( element ); 20 | assertThat( deleted.getInsertedOrDeletedElement() ).isEqualTo( element ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/diff/meta/MetadataDifferenceTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.diff.meta; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | import org.junit.jupiter.api.Test; 10 | 11 | class MetadataDifferenceTest { 12 | 13 | @Test 14 | void constructor_should_not_allow_duplicate_keys() throws Exception { 15 | final MetadataDifference cut = MetadataDifference.of( of( // 16 | new MetadataElementDifference( "a", "b", "c" ), // 17 | new MetadataElementDifference( "a", "e", "f" ) // 18 | ) ); 19 | 20 | assertThat( cut ).hasSize( 1 ); 21 | assertThat( cut ).containsOnlyOnce( new MetadataElementDifference( "a", "e", "f" ) ); 22 | } 23 | 24 | @Test 25 | void constructor_should_allow_unique_keys() throws Exception { 26 | final MetadataDifference cut = MetadataDifference.of( of( // 27 | new MetadataElementDifference( "a", "b", "c" ), // 28 | new MetadataElementDifference( "b", "e", "f" ) // 29 | ) ); 30 | 31 | assertThat( cut ).hasSize( 2 ); 32 | } 33 | 34 | private Set of( final MetadataElementDifference... differences ) { 35 | return new HashSet<>( Arrays.asList( differences ) ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/ui/review/ChangeSetTestUtils.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.ui.review; 2 | 3 | import static org.mockito.Mockito.mock; 4 | 5 | import de.retest.recheck.ui.descriptors.IdentifyingAttributes; 6 | import de.retest.recheck.ui.diff.AttributeDifference; 7 | 8 | public final class ChangeSetTestUtils { 9 | 10 | private ChangeSetTestUtils() {} 11 | 12 | static void fillSuiteChangeSet( final SuiteChangeSet suiteChangeSet ) { 13 | fillTestChangeSet( suiteChangeSet.createTestChangeSet() ); 14 | } 15 | 16 | static void fillTestChangeSet( final TestChangeSet testChangeSet ) { 17 | fillActionChangeSet( testChangeSet.createActionChangeSet() ); 18 | } 19 | 20 | static void fillActionChangeSet( final ActionChangeSet actionChangeSet ) { 21 | actionChangeSet.getIdentAttributeChanges().add( mock( IdentifyingAttributes.class ), 22 | mock( AttributeDifference.class ) ); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/util/DeleteOnCloseFileInputStreamTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.io.TempDir; 12 | 13 | class DeleteOnCloseFileInputStreamTest { 14 | 15 | @Test 16 | void file_should_be_deleted_on_close( @TempDir final Path temp ) throws IOException { 17 | final Path file = temp.resolve( "foo" ); 18 | Files.createFile( file ); 19 | final InputStream in = new DeleteOnCloseFileInputStream( file.toFile() ); 20 | 21 | in.close(); 22 | 23 | assertThat( file ).doesNotExist(); 24 | } 25 | 26 | @Test 27 | void already_deleted_file_should_cause_no_exception( @TempDir final Path temp ) throws IOException { 28 | final Path file = temp.resolve( "bar" ); 29 | Files.createFile( file ); 30 | final InputStream in = new DeleteOnCloseFileInputStream( file.toFile() ); 31 | 32 | Files.delete( file ); 33 | in.close(); 34 | 35 | assertThat( file ).doesNotExist(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/util/ObjectUtilTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import static de.retest.recheck.util.ObjectUtil.nextHashCode; 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import org.junit.Test; 7 | 8 | public class ObjectUtilTest { 9 | 10 | @Test 11 | public void nextHashCode_must_be_order_sensitive() throws Exception { 12 | assertThat( nextHashCode( nextHashCode( nextHashCode( 1, "you" ), "me" ), "them" ) ) 13 | .isNotEqualTo( nextHashCode( nextHashCode( nextHashCode( 1, "them" ), "me" ), "you" ) ); 14 | } 15 | 16 | @Test 17 | public void isObjectToString_should_be_recognized() throws Exception { 18 | assertThat( ObjectUtil.isObjectToString( new Object().toString() ) ).isTrue(); 19 | } 20 | 21 | @Test 22 | public void removeObjectHash_should_be_removed() throws Exception { 23 | assertThat( ObjectUtil.removeObjectHash( new Object().toString() ) ).isEqualTo( "java.lang.Object" ); 24 | } 25 | 26 | @Test 27 | public void isObjectToString_should_be_null_safe() { 28 | ObjectUtil.isObjectToString( null ); 29 | // do not throw exception 30 | } 31 | 32 | @Test 33 | public void removeObjectHash_should_be_null_safe() { 34 | ObjectUtil.removeObjectHash( null ); 35 | // do not throw exception 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/util/OptionalUtilTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Optional; 6 | 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | 10 | class OptionalUtilTest { 11 | 12 | Object value; 13 | Optional present; 14 | Optional absent; 15 | 16 | @BeforeEach 17 | void setUp() throws Exception { 18 | value = new Object(); 19 | present = Optional.of( value ); 20 | absent = Optional.empty(); 21 | } 22 | 23 | @Test 24 | void stream_should_contain_value_if_present() { 25 | assertThat( OptionalUtil.stream( present ) ).containsExactly( value ); 26 | } 27 | 28 | @Test 29 | void stream_should_be_empty_if_absent() throws Exception { 30 | assertThat( OptionalUtil.stream( absent ) ).isEmpty(); 31 | } 32 | 33 | @Test 34 | void or_should_return_given_optional_if_present() throws Exception { 35 | assertThat( OptionalUtil.or( present, () -> absent ) ).isEqualTo( present ); 36 | } 37 | 38 | @Test 39 | void or_should_return_use_supplier_if_absent() throws Exception { 40 | assertThat( OptionalUtil.or( absent, () -> present ) ).isEqualTo( present ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/util/VersionProviderTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.Test; 6 | 7 | public class VersionProviderTest { 8 | 9 | @Test 10 | public void retest_version_is_not_null() { 11 | assertThat( VersionProvider.RECHECK_VERSION ).isNotNull(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/de/retest/recheck/util/junit/vintage/LocaleRule.java: -------------------------------------------------------------------------------- 1 | package de.retest.recheck.util.junit.vintage; 2 | 3 | import java.util.Locale; 4 | 5 | import org.junit.rules.ExternalResource; 6 | 7 | public class LocaleRule extends ExternalResource { 8 | 9 | private static final Locale defaultLocale = Locale.getDefault(); 10 | 11 | private final Locale tempLocale; 12 | 13 | public LocaleRule( final Locale tempLocale ) { 14 | this.tempLocale = tempLocale; 15 | } 16 | 17 | @Override 18 | protected void before() throws Throwable { 19 | Locale.setDefault( tempLocale ); 20 | } 21 | 22 | @Override 23 | protected void after() { 24 | Locale.setDefault( defaultLocale ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/de/retest/util/XsdRegressionTest.java: -------------------------------------------------------------------------------- 1 | package de.retest.util; 2 | 3 | import org.junit.jupiter.params.ParameterizedTest; 4 | import org.junit.jupiter.params.provider.MethodSource; 5 | 6 | import de.retest.recheck.persistence.xml.util.StdXmlClassesProvider; 7 | import de.retest.recheck.util.ApprovalsUtil; 8 | 9 | class XsdRegressionTest { 10 | 11 | /** 12 | * Check the generated XSD of our XML data classes for differences, which possibly indicate the need of a 13 | * corresponding migrator. See src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/ for 14 | * approved/received files. 15 | * 16 | * @param clazz 17 | * The class to be serialized and checked for differences. 18 | */ 19 | @ParameterizedTest 20 | @MethodSource( "getXmlDataClasses" ) 21 | void checkXsd( final Class clazz ) throws Exception { 22 | ApprovalsUtil.verifyMultiXsd( clazz ); 23 | } 24 | 25 | // Wrapper since @MethodSource doesn't support varargs. 26 | static Class[] getXmlDataClasses() { 27 | return StdXmlClassesProvider.getXmlDataClasses(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/resources/ImageUtilsTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/ImageUtilsTest.png -------------------------------------------------------------------------------- /src/test/resources/ImageUtilsTestResize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/ImageUtilsTestResize.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/PageRenderer_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/PageRenderer_1.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/PageRenderer_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/PageRenderer_2.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/PageRenderer_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/PageRenderer_diff.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/fuzzy-diff-img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/fuzzy-diff-img1.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/fuzzy-diff-img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/fuzzy-diff-img2.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/fuzzy-diff-img_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/fuzzy-diff-img_diff.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/img1.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/img2.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/img_diff_exact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/img_diff_exact.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/img_diff_fuzzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/img_diff_fuzzy.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/natural1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/natural1.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/natural1_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/natural1_small.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/natural2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/natural2.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/natural_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/natural_diff.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/natural_small_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/natural_small_diff.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/painted1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/painted1.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/painted2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/painted2.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/image/painted_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/image/painted_diff.png -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/RecheckCapMessageTest.no_golden_master_message_should_be_formatted_properly.approved.txt: -------------------------------------------------------------------------------- 1 | 'SomeSuite': No Golden Master found. First time test was run? Created new Golden Master, so don't forget to commit... 2 | /gm/path/0 3 | /gm/path/0 4 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/RecheckImplIT.diff_should_be_created_accordingly.approved.txt: -------------------------------------------------------------------------------- 1 | A detailed report will be created at '*'. You can review the details by using our CLI (https://github.com/retest/recheck.cli/) or GUI (https://retest.de/review/). 2 | 3 | 1 check(s) in 'de.retest.recheck.RecheckImplIT' found the following difference(s): 4 | Test 'no-filter' has 9 difference(s) in 1 state(s): 5 | check resulted in: 6 | test (title) at 'foo[1]/bar[1]': 7 | foo-1: expected="bar-1", actual="bar-3" 8 | foo-3: expected="bar-3", actual="bar-1" 9 | same (same-id) at 'foo[1]/bar[1]/same[1]': 10 | bar-1: expected="bar-1", actual="bar-1-change" 11 | bar-2: expected="bar-2", actual="null" 12 | bar-3: expected="bar-3", actual="(default or absent)" 13 | bar-2-change: expected="(default or absent)", actual="bar-2" 14 | bar-3-change: expected="(default or absent)", actual="bar-3" 15 | delete (delete-id) at 'foo[1]/bar[1]/remove[1]/delete[1]': 16 | was deleted 17 | insert (insert-id) at 'foo[1]/bar[1]/add[1]/insert[1]': 18 | was inserted 19 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/RecheckImplIT.diff_should_be_created_if_filtered.approved.txt: -------------------------------------------------------------------------------- 1 | A detailed report will be created at '*'. You can review the details by using our CLI (https://github.com/retest/recheck.cli/) or GUI (https://retest.de/review/). 2 | 3 | 1 check(s) in 'de.retest.recheck.RecheckImplIT' found the following difference(s): 4 | Test 'filter' has 4 difference(s) in 1 state(s): 5 | check resulted in: 6 | test (title) at 'foo[1]/bar[1]': 7 | foo-1: expected="bar-1", actual="bar-3" 8 | foo-3: expected="bar-3", actual="bar-1" 9 | delete (delete-id) at 'foo[1]/bar[1]/remove[1]/delete[1]': 10 | was deleted 11 | insert (insert-id) at 'foo[1]/bar[1]/add[1]/insert[1]': 12 | was inserted 13 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/RecheckImplIT.diff_should_be_created_with_deleted_filtered.approved.txt: -------------------------------------------------------------------------------- 1 | A detailed report will be created at '*'. You can review the details by using our CLI (https://github.com/retest/recheck.cli/) or GUI (https://retest.de/review/). 2 | 3 | 1 check(s) in 'de.retest.recheck.RecheckImplIT' found the following difference(s): 4 | Test 'filter-deleted' has 8 difference(s) in 1 state(s): 5 | check resulted in: 6 | test (title) at 'foo[1]/bar[1]': 7 | foo-1: expected="bar-1", actual="bar-3" 8 | foo-3: expected="bar-3", actual="bar-1" 9 | same (same-id) at 'foo[1]/bar[1]/same[1]': 10 | bar-1: expected="bar-1", actual="bar-1-change" 11 | bar-2: expected="bar-2", actual="null" 12 | bar-3: expected="bar-3", actual="(default or absent)" 13 | bar-2-change: expected="(default or absent)", actual="bar-2" 14 | bar-3-change: expected="(default or absent)", actual="bar-3" 15 | insert (insert-id) at 'foo[1]/bar[1]/add[1]/insert[1]': 16 | was inserted 17 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/RecheckImplIT.diff_should_handle_legacy_spaces_accordingly.approved.txt: -------------------------------------------------------------------------------- 1 | A detailed report will be created at '*'. You can review the details by using our CLI (https://github.com/retest/recheck.cli/) or GUI (https://retest.de/review/). 2 | 3 | 1 check(s) in 'de.retest.recheck.RecheckImplIT legacy spaces' found the following difference(s): 4 | Test 'with legacy spaces' has 9 difference(s) in 1 state(s): 5 | check resulted in: 6 | test (title) at 'foo[1]/bar[1]': 7 | foo-1: expected="bar-1", actual="bar-3" 8 | foo-3: expected="bar-3", actual="bar-1" 9 | same (same-id) at 'foo[1]/bar[1]/same[1]': 10 | bar-1: expected="bar-1", actual="bar-1-change" 11 | bar-2: expected="bar-2", actual="null" 12 | bar-3: expected="bar-3", actual="(default or absent)" 13 | bar-2-change: expected="(default or absent)", actual="bar-2" 14 | bar-3-change: expected="(default or absent)", actual="bar-3" 15 | delete (delete-id) at 'foo[1]/bar[1]/remove[1]/delete[1]': 16 | was deleted 17 | insert (insert-id) at 'foo[1]/bar[1]/add[1]/insert[1]': 18 | was inserted 19 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/RecheckImplIT.diff_should_handle_spaces_accordingly.approved.txt: -------------------------------------------------------------------------------- 1 | A detailed report will be created at '*'. You can review the details by using our CLI (https://github.com/retest/recheck.cli/) or GUI (https://retest.de/review/). 2 | 3 | 1 check(s) in 'de.retest.recheck.RecheckImplIT spaces' found the following difference(s): 4 | Test 'with spaces' has 9 difference(s) in 1 state(s): 5 | check resulted in: 6 | test (title) at 'foo[1]/bar[1]': 7 | foo-1: expected="bar-1", actual="bar-3" 8 | foo-3: expected="bar-3", actual="bar-1" 9 | same (same-id) at 'foo[1]/bar[1]/same[1]': 10 | bar-1: expected="bar-1", actual="bar-1-change" 11 | bar-2: expected="bar-2", actual="null" 12 | bar-3: expected="bar-3", actual="(default or absent)" 13 | bar-2-change: expected="(default or absent)", actual="bar-2" 14 | bar-3-change: expected="(default or absent)", actual="bar-3" 15 | delete (delete-id) at 'foo[1]/bar[1]/remove[1]/delete[1]': 16 | was deleted 17 | insert (insert-id) at 'foo[1]/bar[1]/add[1]/insert[1]': 18 | was inserted 19 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/RecheckImplIT.diff_should_ignore_everything_but_include_deleted_and_same_attributes_with_change_suffix.approved.txt: -------------------------------------------------------------------------------- 1 | A detailed report will be created at '*'. You can review the details by using our CLI (https://github.com/retest/recheck.cli/) or GUI (https://retest.de/review/). 2 | 3 | 1 check(s) in 'de.retest.recheck.RecheckImplIT' found the following difference(s): 4 | Test 'with_exclude' has 3 difference(s) in 1 state(s): 5 | check resulted in: 6 | same (same-id) at 'foo[1]/bar[1]/same[1]': 7 | bar-2-change: expected="(default or absent)", actual="bar-2" 8 | bar-3-change: expected="(default or absent)", actual="bar-3" 9 | delete (delete-id) at 'foo[1]/bar[1]/remove[1]/delete[1]': 10 | was deleted 11 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/elementcollection/ElementCollectionPersistenceTest.check_persisted_xml.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Window[1] 9 | 1 10 | de.retest.recheck.elementcollection.ElementCollectionPersistenceTest 11 | 12 | 13 | 14 | 15 | color, text 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ignore/file.filter: -------------------------------------------------------------------------------- 1 | matcher: id=foo, attribute=font -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ignore/file.filter.js: -------------------------------------------------------------------------------- 1 | function matches(element, diff) { 2 | return true; 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/persistence/bin/1.6.0.report: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/recheck/persistence/bin/1.6.0.report -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/persistence/bin/old.report: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/de/retest/recheck/persistence/bin/old.report -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/persistence/migration/RemoveElementTransformerIT.extended_xml_should_be_removed_correctly.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test 6 | 7 | 8 | Test3 9 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/persistence/migration/RemoveElementTransformerIT.simple_xml_element_should_be_removed.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/persistence/xml/AttributesAdapterTest.inheriting_attributes_should_be_persistable.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Window[1]/path[1]/component[1] 8 | 1 9 | javax.swing.JButton 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/persistence/xml/XmlFolderPersistenceTest.simple_save_to_folder.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/persistence/xml/XmlZipPersistenceTest.simple_save_to_file.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/printer/ActionReplayResultPrinterTest.toString_should_not_print_child_differences_if_insertion_or_deletion.approved.txt: -------------------------------------------------------------------------------- 1 | Start Sut resulted in: 2 | type (retestId) at 'html[1]/body[1]': 3 | foo-1: expected="bar-1", actual="bar1" 4 | foo-2: expected="bar-2", actual="bar2" 5 | foo-3: expected="bar-3", actual="bar3" 6 | type (retestId) at 'html[1]/body[1]/div[1]': 7 | was deleted 8 | type (retestId) at 'html[1]/body[1]/div[2]': 9 | foo-1: expected="bar-1", actual="bar1" 10 | foo-2: expected="bar-2", actual="bar2" 11 | foo-3: expected="bar-3", actual="bar3" 12 | type (retestId) at 'html[1]/body[1]/div[2]/div[1]': 13 | was deleted 14 | type (retestId) at 'html[1]/body[1]/div[2]/div[2]': 15 | foo-1: expected="bar-1", actual="bar1" 16 | foo-2: expected="bar-2", actual="bar2" 17 | foo-3: expected="bar-3", actual="bar3" 18 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/review/workers/legacy-recheck.ignore: -------------------------------------------------------------------------------- 1 | # Matcher 2 | matcher: class=some-class 3 | matcher: class=one two 4 | matcher: class=some-class, attribute: font 5 | matcher: class=one two, attribute-regex: .*color 6 | matcher: id=banner 7 | matcher: id=title, attribute: font 8 | matcher: retestid=banner 9 | matcher: retestid=banner, attribute: outline 10 | matcher: retestid=banner, attribute-regex: .*color 11 | matcher: xpath=html[1]/div[1]/div[1]/div[2] 12 | matcher: xpath=/html/div/div/div[2], attribute: background-url 13 | matcher: type=div, attribute-regex: .*color 14 | 15 | # Attributes 16 | attribute=outline 17 | attribute=possible-*regex 18 | attribute-regex= .* 19 | 20 | # Misc 21 | pixel-diff=5 22 | pixel-diff=5.0 23 | 24 | # Or ignore concrete values, but ensure they follow a specific pattern 25 | value-regex=\d\d\.\d\d\.\d\d\d\d 26 | attribute=text, value-regex=\d\d\.\d\d\.\d\d\d\d 27 | matcher: id=date-field, value-regex=\d\d\.\d\d\.\d\d\d\d 28 | matcher: id=date-field, attribute=text, value-regex=\d\d\.\d\d\.\d\d\d\d 29 | 30 | # Whitespace 31 | 32 | # Tab 33 | 34 | # Leading whitespace 35 | attribute:foo 36 | 37 | # Error: wrong syntax 38 | attribute:bar 39 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/review/workers/recheck.ignore: -------------------------------------------------------------------------------- 1 | # Matcher 2 | matcher: class=some-class 3 | matcher: class=one two 4 | matcher: class=some-class, attribute=font 5 | matcher: class=one two, attribute-regex=.*color 6 | matcher: id=banner 7 | matcher: id=title, attribute=font 8 | matcher: retestid=banner 9 | matcher: retestid=banner, attribute=outline 10 | matcher: retestid=banner, attribute-regex=.*color 11 | matcher: xpath=html[1]/div[1]/div[1]/div[2] 12 | matcher: xpath=/html/div/div/div[2], attribute=background-url 13 | matcher: type=div, attribute-regex=.*color 14 | 15 | # Attributes 16 | attribute=outline 17 | attribute=possible-*regex 18 | attribute-regex= .* 19 | 20 | # Misc 21 | pixel-diff=5px 22 | pixel-diff=5.0px 23 | 24 | # Or ignore concrete values, but ensure they follow a specific pattern 25 | value-regex=\d\d\.\d\d\.\d\d\d\d 26 | attribute=text, value-regex=\d\d\.\d\d\.\d\d\d\d 27 | matcher: id=date-field, value-regex=\d\d\.\d\d\.\d\d\d\d 28 | matcher: id=date-field, attribute=text, value-regex=\d\d\.\d\d\.\d\d\d\d 29 | 30 | # Whitespace 31 | 32 | # Tab 33 | 34 | # Leading whitespace 35 | attribute:foo 36 | 37 | # Error: wrong syntax 38 | attribute:bar 39 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/AttributesDifferenceFinderTest.attributesDifference_with_different_key_and_different_values.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | value1 4 | 5 | 6 | value2 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/AttributesDifferenceFinderTest.attributesDifference_with_less_expected_than_actual.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | value2 4 | different-value 5 | 6 | 7 | value3 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/AttributesDifferenceFinderTest.attributesDifference_with_more_expected_than_actual.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | value2 4 | different-value 5 | 6 | 7 | value3 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/AttributesDifferenceFinderTest.attributesDifference_with_the_same_key_but_different_values.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | value1 4 | value2 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/IdentifyingAttributesDifferenceFinderTest.differences_should_be_recognized_accordingly.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | parentPath[1]/type[1] 3 | 1 4 | de.retest.recheck.ui.diff.IdentifyingAttributesDifferenceFinderTest$Type 5 | 6 | parentPath[1]/type[1] 7 | anotherParentPath[1]/anotherType[1] 8 | 9 | 10 | de.retest.recheck.ui.diff.IdentifyingAttributesDifferenceFinderTest$Type 11 | de.retest.recheck.ui.diff.IdentifyingAttributesDifferenceFinderTest$AnotherType 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/IdentifyingAttributesDifferenceFinderTest.different_paths_and_components_should_be_recognized_accordingly.approved.xml: -------------------------------------------------------------------------------- 1 | 2 | AnotherType[1] 3 | 1 4 | de.retest.recheck.ui.diff.IdentifyingAttributesDifferenceFinderTest$AnotherType 5 | 6 | AnotherType[1] 7 | Type[1] 8 | 9 | 10 | de.retest.recheck.ui.diff.IdentifyingAttributesDifferenceFinderTest$AnotherType 11 | de.retest.recheck.ui.diff.IdentifyingAttributesDifferenceFinderTest$Type 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/RootElementDifferenceFinderTest.actual_root_element_is_null.approved.txt: -------------------------------------------------------------------------------- 1 | WindowIdentifyingAttributesDifference [expected=Window[1], actual=null] 2 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/RootElementDifferenceFinderTest.different_root_element_with_same_components_should_match.approved.txt: -------------------------------------------------------------------------------- 1 | [WindowIdentifyingAttributesDifference expected path: Window[1] expected type: de.retest.recheck.ui.diff.RootElementDifferenceFinderTest$Window - actual path: Other[1] actual type: javax.swing.JDialog] 2 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/RootElementDifferenceFinderTest.expected_and_actual_root_element_are_different.approved.txt: -------------------------------------------------------------------------------- 1 | WindowIdentifyingAttributesDifference expected type: de.retest.recheck.ui.diff.RootElementDifferenceFinderTest$Window - actual type: de.retest.recheck.ui.diff.RootElementDifferenceFinderTest$OtherWindow 2 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/RootElementDifferenceFinderTest.expected_root_element_is_null.approved.txt: -------------------------------------------------------------------------------- 1 | WindowIdentifyingAttributesDifference [expected=null, actual=Window[1]] 2 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/RootElementDifferenceFinderTest.lists_of_different_root_element_are_matched_even_if_the_order_is_different.approved.txt: -------------------------------------------------------------------------------- 1 | [Window[1]: 2 | at: Window[1]: 3 | criterion: expected="null", actual="true", Window[1]: 4 | at: Window[1]: 5 | criterion: expected="null", actual="true"] 6 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/RootElementDifferenceFinderTest.lists_of_root_element_with_different_window_titles_are_matched.approved.txt: -------------------------------------------------------------------------------- 1 | [Window[1]: 2 | at: Window[1]: 3 | expected type: de.retest.recheck.ui.diff.RootElementDifferenceFinderTest$Window - actual type: de.retest.recheck.ui.diff.RootElementDifferenceFinderTest$OtherWindow] 4 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/recheck/ui/diff/RootElementDifferenceFinderTest.lists_of_root_element_with_different_window_titles_are_not_matched.approved.txt: -------------------------------------------------------------------------------- 1 | [Window[1]: 2 | at: Window[1]: 3 | [expected=Window[1], actual=null], Window[1]: 4 | at: Window[1]: 5 | [expected=null, actual=Window[1]]] 6 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/ActionParameter.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/ActionSequence.approved.xsd: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/Attribute.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/AttributeDifference.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/CapturedSuite.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/ContextAttribute.approved.xsd: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/DefaultAttribute.approved.xsd: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/ElementDifference.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/OutlineAttribute.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/PathAttribute.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/ReTestXmlDataContainer.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/RootElementDifference.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/StateDifference.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/StringAttribute.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/SuffixAttribute.approved.xsd: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/Test.approved.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/de/retest/util/XsdRegressionTest.checkXsd/TextAttribute.approved.xsd: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/test/resources/persistence/empty.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/persistence/empty.zip -------------------------------------------------------------------------------- /src/test/resources/persistence/simple_folder_persisted/retest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/test/resources/persistence/simple_zip_persisted.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/persistence/simple_zip_persisted.zip -------------------------------------------------------------------------------- /src/test/resources/recheck/ApplyChangesToStatesFlowTest/check_GUI_with_review_license.launch.recheck: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retest/recheck/abaa8a364adafe7e87d1201e2b0aac148d76ef48/src/test/resources/recheck/ApplyChangesToStatesFlowTest/check_GUI_with_review_license.launch.recheck --------------------------------------------------------------------------------