├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── build-binaries.yml │ ├── codeql-analysis.yml │ ├── main.yml │ ├── maven-publish.yml │ └── release-to-maven-central.yml ├── .gitignore ├── .mvn ├── jvm.config └── wrapper │ └── maven-wrapper.properties ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cats_autocomplete ├── files ├── README.md ├── errorLeaks.txt ├── functionalFuzzer.yml ├── fuzzConfig.properties ├── headers.yml ├── mutators │ ├── first.yml │ ├── second.yml │ └── third.yml ├── nosql.txt ├── pathsOrder.txt ├── referenceFields.yml ├── securityFuzzer.yml └── xss.txt ├── images ├── cats_logo_dark.svg ├── cats_logo_light.svg ├── index_html.png ├── run_result.png ├── test_details_1.png ├── test_details_2.png └── tests_result.png ├── lib ├── okhttp-4.12.0-CATS-javadoc.jar ├── okhttp-4.12.0-CATS-sources.jar ├── okhttp-4.12.0-CATS.jar ├── okhttp-4.12.0-CATS.module ├── okhttp-4.12.0-CATS.pom ├── swagger-parser-v3-2.1.27-CATS-javadoc.jar ├── swagger-parser-v3-2.1.27-CATS-sources.jar ├── swagger-parser-v3-2.1.27-CATS.jar ├── swagger-parser-v3-2.1.27-CATS.pom ├── swagger-parser-v3-2.1.29-CATS-javadoc.jar ├── swagger-parser-v3-2.1.29-CATS-sources.jar ├── swagger-parser-v3-2.1.29-CATS.jar └── swagger-parser-v3-2.1.29-CATS.pom ├── lombok.config ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── endava │ │ └── cats │ │ ├── CatsMain.java │ │ ├── ReflectionConfig.java │ │ ├── annotations │ │ ├── ControlCharFuzzer.java │ │ ├── DryRun.java │ │ ├── EmojiFuzzer.java │ │ ├── FieldFuzzer.java │ │ ├── HeaderFuzzer.java │ │ ├── HttpFuzzer.java │ │ ├── Linter.java │ │ ├── SanitizeAndValidate.java │ │ ├── SecondPhaseFuzzer.java │ │ ├── SpecialFuzzer.java │ │ ├── TrimAndValidate.java │ │ ├── ValidateAndSanitize.java │ │ ├── ValidateAndTrim.java │ │ └── WhitespaceFuzzer.java │ │ ├── aop │ │ ├── DryRunAspect.java │ │ └── DryRunEntry.java │ │ ├── args │ │ ├── ApiArguments.java │ │ ├── AuthArguments.java │ │ ├── CheckArguments.java │ │ ├── FilesArguments.java │ │ ├── FilterArguments.java │ │ ├── IgnoreArguments.java │ │ ├── MatchArguments.java │ │ ├── NamingArguments.java │ │ ├── ProcessingArguments.java │ │ ├── ReportingArguments.java │ │ ├── StopArguments.java │ │ └── UserArguments.java │ │ ├── command │ │ ├── CatsCommand.java │ │ ├── ExplainCommand.java │ │ ├── GenerateCommand.java │ │ ├── InfoCommand.java │ │ ├── LintCommand.java │ │ ├── ListCommand.java │ │ ├── RandomCommand.java │ │ ├── ReplayCommand.java │ │ ├── RunCommand.java │ │ ├── StatsCommand.java │ │ ├── TemplateFuzzCommand.java │ │ ├── ValidateCommand.java │ │ └── model │ │ │ ├── ConfigOptions.java │ │ │ ├── FuzzerListEntry.java │ │ │ ├── MutatorEntry.java │ │ │ ├── PathDetailsEntry.java │ │ │ ├── PathListEntry.java │ │ │ └── ValidContractEntry.java │ │ ├── context │ │ └── CatsGlobalContext.java │ │ ├── dsl │ │ ├── CatsDSLParser.java │ │ ├── api │ │ │ └── Parser.java │ │ └── impl │ │ │ ├── AuthScriptProviderParser.java │ │ │ ├── EnvVariableParser.java │ │ │ ├── NoOpParser.java │ │ │ └── SpringELParser.java │ │ ├── exception │ │ └── CatsException.java │ │ ├── factory │ │ └── FuzzingDataFactory.java │ │ ├── fuzzer │ │ ├── api │ │ │ └── Fuzzer.java │ │ ├── contract │ │ │ ├── ArrayWithoutItemsLinter.java │ │ │ ├── CollectionPaginationLinter.java │ │ │ ├── DeleteHasBodyLinter.java │ │ │ ├── EmptyPathsLinter.java │ │ │ ├── EmptyRequestSchemaLinter.java │ │ │ ├── EmptyResponseSchemaLinter.java │ │ │ ├── GetHasBodyLinter.java │ │ │ ├── HeadHasBodyLinter.java │ │ │ ├── HeadersCaseLinter.java │ │ │ ├── HttpMethodConsistencyErrorLinter.java │ │ │ ├── HttpMethodConsistencyWarnLinter.java │ │ │ ├── HttpStatusCodeInRangeLinter.java │ │ │ ├── JsonObjectsCaseLinter.java │ │ │ ├── MultipleSuccessCodesLinter.java │ │ │ ├── OperationIdVerbPrefixLinter.java │ │ │ ├── PatchWithoutBodyLinter.java │ │ │ ├── PathCaseLinter.java │ │ │ ├── PathNounsLinter.java │ │ │ ├── PathPluralsLinter.java │ │ │ ├── PathTagsLinter.java │ │ │ ├── PostWithoutBodyLinter.java │ │ │ ├── PutWithoutBodyLinter.java │ │ │ ├── QueryParamsCaseLinter.java │ │ │ ├── RecommendedHttpCodesLinter.java │ │ │ ├── ResponsesWithBodiesLinter.java │ │ │ ├── SecuritySchemesLinter.java │ │ │ ├── TopLevelElementsLinter.java │ │ │ ├── TracingHeadersLinter.java │ │ │ ├── UniqueOperationIdsLinter.java │ │ │ ├── UnusedExamplesLinter.java │ │ │ ├── UnusedHeadersLinter.java │ │ │ ├── UnusedParametersLinter.java │ │ │ ├── UnusedRequestBodiesLinter.java │ │ │ ├── UnusedResponsesLinter.java │ │ │ ├── UnusedSchemasLinter.java │ │ │ ├── VersionsLinter.java │ │ │ ├── XmlContentTypeLinter.java │ │ │ ├── base │ │ │ │ ├── AbstractRequestBodyLinter.java │ │ │ │ ├── AbstractRequestWithoutBodyLinter.java │ │ │ │ ├── AbstractUnusedElementsLinter.java │ │ │ │ └── BaseLinter.java │ │ │ └── util │ │ │ │ └── HttpMethodConsistencyAnalyzer.java │ │ ├── executor │ │ │ ├── FieldsIteratorExecutor.java │ │ │ ├── FieldsIteratorExecutorContext.java │ │ │ ├── HeadersIteratorExecutor.java │ │ │ ├── HeadersIteratorExecutorContext.java │ │ │ ├── SimpleExecutor.java │ │ │ └── SimpleExecutorContext.java │ │ ├── fields │ │ │ ├── AbugidasInStringFieldsSanitizeValidateFuzzer.java │ │ │ ├── AbugidasInStringFieldsValidateSanitizeFuzzer.java │ │ │ ├── DecimalFieldsLeftBoundaryFuzzer.java │ │ │ ├── DecimalFieldsRightBoundaryFuzzer.java │ │ │ ├── DecimalNumbersInIntegerFieldsFuzzer.java │ │ │ ├── DefaultValuesInFieldsFuzzer.java │ │ │ ├── EmptyStringsInFieldsFuzzer.java │ │ │ ├── EnumCaseVariantFieldsFuzzer.java │ │ │ ├── ExamplesFieldsFuzzer.java │ │ │ ├── ExtremeNegativeNumbersInDecimalFieldsFuzzer.java │ │ │ ├── ExtremeNegativeNumbersInIntegerFieldsFuzzer.java │ │ │ ├── ExtremePositiveNumbersInDecimalFieldsFuzzer.java │ │ │ ├── ExtremePositiveNumbersInIntegerFieldsFuzzer.java │ │ │ ├── InsertWhitespacesInFieldNamesFieldFuzzer.java │ │ │ ├── IntegerFieldsLeftBoundaryFuzzer.java │ │ │ ├── IntegerFieldsRightBoundaryFuzzer.java │ │ │ ├── InvalidReferencesFieldsFuzzer.java │ │ │ ├── InvalidValuesInEnumsFieldsFuzzer.java │ │ │ ├── IterateThroughEnumValuesFieldsFuzzer.java │ │ │ ├── LowercaseExpandingBytesInStringFieldsFuzzer.java │ │ │ ├── LowercaseExpandingLengthInStringFieldsFuzzer.java │ │ │ ├── MaxLengthExactValuesInStringFieldsFuzzer.java │ │ │ ├── MaximumExactNumbersInNumericFieldsFuzzer.java │ │ │ ├── MinGreaterThanMaxFieldsFuzzer.java │ │ │ ├── MinLengthExactValuesInStringFieldsFuzzer.java │ │ │ ├── MinimumExactNumbersInNumericFieldsFuzzer.java │ │ │ ├── NewFieldsFuzzer.java │ │ │ ├── NullValuesInFieldsFuzzer.java │ │ │ ├── OverflowArraySizeFieldsFuzzer.java │ │ │ ├── OverflowMapSizeFieldsFuzzer.java │ │ │ ├── RandomStringsInBooleanFieldsFuzzer.java │ │ │ ├── RemoveFieldsFuzzer.java │ │ │ ├── ReplaceArraysWithPrimitivesFieldsFuzzer.java │ │ │ ├── ReplaceArraysWithSimpleObjectsFieldsFuzzer.java │ │ │ ├── ReplaceObjectsWithArraysFieldsFuzzer.java │ │ │ ├── ReplaceObjectsWithPrimitivesFieldsFuzzer.java │ │ │ ├── ReplacePrimitivesWithArraysFieldsFuzzer.java │ │ │ ├── ReplacePrimitivesWithObjectsFieldsFuzzer.java │ │ │ ├── StringFieldsLeftBoundaryFuzzer.java │ │ │ ├── StringFieldsRightBoundaryFuzzer.java │ │ │ ├── StringFormatAlmostValidValuesFuzzer.java │ │ │ ├── StringFormatTotallyWrongValuesFuzzer.java │ │ │ ├── StringsInNumericFieldsFuzzer.java │ │ │ ├── TemporalLogicFieldsFuzzer.java │ │ │ ├── UppercaseExpandingBytesInStringFieldsFuzzer.java │ │ │ ├── UppercaseExpandingLengthInStringFieldsFuzzer.java │ │ │ ├── UserDictionaryFieldsFuzzer.java │ │ │ ├── VeryLargeDecimalsInNumericFieldsFuzzer.java │ │ │ ├── VeryLargeIntegersInNumericFieldsFuzzer.java │ │ │ ├── VeryLargeStringsInFieldsFuzzer.java │ │ │ ├── VeryLargeUnicodeStringsInFieldsFuzzer.java │ │ │ ├── ZalgoTextInFieldsSanitizeValidateFuzzer.java │ │ │ ├── ZalgoTextInFieldsValidateSanitizeFuzzer.java │ │ │ ├── ZeroWidthCharsInNamesFieldsFuzzer.java │ │ │ ├── ZeroWidthCharsInValuesFieldsSanitizeValidateFuzzer.java │ │ │ ├── ZeroWidthCharsInValuesFieldsValidateSanitizeFuzzer.java │ │ │ ├── base │ │ │ │ ├── BaseBoundaryFieldFuzzer.java │ │ │ │ ├── BaseEnumIteratorFieldsFuzzer.java │ │ │ │ ├── BaseFieldsFuzzer.java │ │ │ │ ├── BaseReplaceFieldsFuzzer.java │ │ │ │ ├── CustomFuzzerBase.java │ │ │ │ ├── ExactValuesInFieldsFuzzer.java │ │ │ │ ├── Expect4XXForRequiredBaseFieldsFuzzer.java │ │ │ │ ├── ExpectOnly2XXBaseFieldsFuzzer.java │ │ │ │ ├── ExpectOnly4XXBaseFieldsFuzzer.java │ │ │ │ ├── InvisibleCharsBaseTrimValidateFuzzer.java │ │ │ │ └── TwoXXorFourXXReplaceStringsFuzzer.java │ │ │ ├── leading │ │ │ │ ├── LeadingControlCharsInFieldsTrimValidateFuzzer.java │ │ │ │ ├── LeadingControlCharsInFieldsValidateTrimFuzzer.java │ │ │ │ ├── LeadingMultiCodePointEmojisInFieldsTrimValidateFuzzer.java │ │ │ │ ├── LeadingMultiCodePointEmojisInFieldsValidateTrimFuzzer.java │ │ │ │ ├── LeadingSingleCodePointEmojisInFieldsTrimValidateFuzzer.java │ │ │ │ ├── LeadingSingleCodePointEmojisInFieldsValidateTrimFuzzer.java │ │ │ │ ├── LeadingWhitespacesInFieldsTrimValidateFuzzer.java │ │ │ │ └── LeadingWhitespacesInFieldsValidateTrimFuzzer.java │ │ │ ├── only │ │ │ │ ├── InvisibleCharsOnlyTrimValidateFuzzer.java │ │ │ │ ├── InvisibleCharsOnlyValidateTrimFuzzer.java │ │ │ │ ├── OnlyControlCharsInFieldsTrimValidateFuzzer.java │ │ │ │ ├── OnlyControlCharsInFieldsValidateTrimFuzzer.java │ │ │ │ ├── OnlyMultiCodePointEmojisInFieldsTrimValidateFuzzer.java │ │ │ │ ├── OnlyMultiCodePointEmojisInFieldsValidateTrimFuzzer.java │ │ │ │ ├── OnlySingleCodePointEmojisInFieldsTrimValidateFuzzer.java │ │ │ │ ├── OnlySingleCodePointEmojisInFieldsValidateTrimFuzzer.java │ │ │ │ ├── OnlyWhitespacesInFieldsTrimValidateFuzzer.java │ │ │ │ └── OnlyWhitespacesInFieldsValidateTrimFuzzer.java │ │ │ ├── trailing │ │ │ │ ├── TrailingControlCharsInFieldsTrimValidateFuzzer.java │ │ │ │ ├── TrailingControlCharsInFieldsValidateTrimFuzzer.java │ │ │ │ ├── TrailingMultiCodePointEmojisInFieldsTrimValidateFuzzer.java │ │ │ │ ├── TrailingMultiCodePointEmojisInFieldsValidateTrimFuzzer.java │ │ │ │ ├── TrailingSingleCodePointEmojisInFieldsTrimValidateFuzzer.java │ │ │ │ ├── TrailingSingleCodePointEmojisInFieldsValidateTrimFuzzer.java │ │ │ │ ├── TrailingWhitespacesInFieldsTrimValidateFuzzer.java │ │ │ │ └── TrailingWhitespacesInFieldsValidateTrimFuzzer.java │ │ │ └── within │ │ │ │ ├── WithinControlCharsInStringFieldsSanitizeValidateFuzzer.java │ │ │ │ ├── WithinControlCharsInStringFieldsValidateSanitizeFuzzer.java │ │ │ │ ├── WithinMultiCodePointEmojisInStringFieldsTrimValidateFuzzer.java │ │ │ │ ├── WithinMultiCodePointEmojisInStringFieldsValidateTrimFuzzer.java │ │ │ │ ├── WithinSingleCodePointEmojisInStringFieldsTrimValidateFuzzer.java │ │ │ │ └── WithinSingleCodePointEmojisInStringFieldsValidateTrimFuzzer.java │ │ ├── headers │ │ │ ├── AbugidasInHeadersFuzzer.java │ │ │ ├── AcceptLanguageHeadersFuzzer.java │ │ │ ├── CRLFHeadersFuzzer.java │ │ │ ├── CheckSecurityHeadersFuzzer.java │ │ │ ├── DummyAcceptHeadersFuzzer.java │ │ │ ├── DummyContentLengthHeadersFuzzer.java │ │ │ ├── DummyContentTypeHeadersFuzzer.java │ │ │ ├── DummyTransferEncodingHeadersFuzzer.java │ │ │ ├── DuplicateHeadersFuzzer.java │ │ │ ├── EmptyStringsInHeadersFuzzer.java │ │ │ ├── ExtraHeadersFuzzer.java │ │ │ ├── InvalidContentLengthHeadersFuzzer.java │ │ │ ├── LargeNumberOfRandomAlphanumericHeadersFuzzer.java │ │ │ ├── LargeNumberOfRandomHeadersFuzzer.java │ │ │ ├── RemoveHeadersFuzzer.java │ │ │ ├── ResponseHeadersMatchContractHeadersFuzzer.java │ │ │ ├── UnsupportedAcceptHeadersFuzzer.java │ │ │ ├── UnsupportedContentTypesHeadersFuzzer.java │ │ │ ├── UserDictionaryHeadersFuzzer.java │ │ │ ├── VeryLargeStringsInHeadersFuzzer.java │ │ │ ├── VeryLargeUnicodeStringsInHeadersFuzzer.java │ │ │ ├── ZalgoTextInHeadersFuzzer.java │ │ │ ├── ZeroWidthCharsInNamesHeadersFuzzer.java │ │ │ ├── ZeroWidthCharsInValuesHeadersFuzzer.java │ │ │ ├── base │ │ │ │ ├── BaseHeadersFuzzer.java │ │ │ │ ├── BaseHeadersFuzzerContext.java │ │ │ │ ├── BaseRandomHeadersFuzzer.java │ │ │ │ └── BaseSecurityChecksHeadersFuzzer.java │ │ │ ├── leading │ │ │ │ ├── LeadingControlCharsInHeadersFuzzer.java │ │ │ │ ├── LeadingMultiCodePointEmojisInHeadersFuzzer.java │ │ │ │ ├── LeadingSingleCodePointEmojisInHeadersFuzzer.java │ │ │ │ ├── LeadingSpacesInHeadersFuzzer.java │ │ │ │ └── LeadingWhitespacesInHeadersFuzzer.java │ │ │ ├── only │ │ │ │ ├── OnlyControlCharsInHeadersFuzzer.java │ │ │ │ ├── OnlyMultiCodePointEmojisInHeadersFuzzer.java │ │ │ │ ├── OnlySingleCodePointEmojisInHeadersFuzzer.java │ │ │ │ ├── OnlySpacesInHeadersFuzzer.java │ │ │ │ └── OnlyWhitespacesInHeadersFuzzer.java │ │ │ └── trailing │ │ │ │ ├── TrailingControlCharsInHeadersFuzzer.java │ │ │ │ ├── TrailingMultiCodePointEmojisHeadersFuzzer.java │ │ │ │ ├── TrailingSingleCodePointEmojisHeadersFuzzer.java │ │ │ │ ├── TrailingSpacesInHeadersFuzzer.java │ │ │ │ └── TrailingWhitespacesInHeadersFuzzer.java │ │ ├── http │ │ │ ├── BaseHttpWithPayloadSimpleFuzzer.java │ │ │ ├── BypassAuthenticationFuzzer.java │ │ │ ├── CheckDeletedResourcesNotAvailableFuzzer.java │ │ │ ├── CustomHttpMethodsFuzzer.java │ │ │ ├── DummyRequestFuzzer.java │ │ │ ├── EmptyBodyFuzzer.java │ │ │ ├── EmptyJsonArrayBodyFuzzer.java │ │ │ ├── EmptyJsonBodyFuzzer.java │ │ │ ├── HappyPathFuzzer.java │ │ │ ├── HttpMethodFuzzerUtil.java │ │ │ ├── HttpMethodsFuzzer.java │ │ │ ├── InsertRandomValuesInBodyFuzzer.java │ │ │ ├── MalformedJsonFuzzer.java │ │ │ ├── NonRestHttpMethodsFuzzer.java │ │ │ ├── NullBodyFuzzer.java │ │ │ ├── NullUnicodeBodyFuzzer.java │ │ │ ├── NullUnicodeSymbolBodyFuzzer.java │ │ │ ├── RandomDummyInvalidJsonBodyFuzzer.java │ │ │ ├── RandomNegativeDecimalBodyFuzzer.java │ │ │ ├── RandomNegativeIntegerBodyFuzzer.java │ │ │ ├── RandomPositiveDecimalBodyFuzzer.java │ │ │ ├── RandomPositiveIntegerBodyFuzzer.java │ │ │ ├── RandomResourcesFuzzer.java │ │ │ ├── RandomStringBodyFuzzer.java │ │ │ ├── RandomUnicodeBodyFuzzer.java │ │ │ ├── ZeroDecimalBodyFuzzer.java │ │ │ └── ZeroIntegerBodyFuzzer.java │ │ └── special │ │ │ ├── CustomFuzzerUtil.java │ │ │ ├── FunctionalFuzzer.java │ │ │ ├── RandomFuzzer.java │ │ │ ├── SecurityFuzzer.java │ │ │ ├── TemplateFuzzer.java │ │ │ └── mutators │ │ │ ├── StringMutationUtils.java │ │ │ ├── api │ │ │ ├── BodyMutator.java │ │ │ ├── CustomMutator.java │ │ │ ├── CustomMutatorConfig.java │ │ │ ├── CustomMutatorKeywords.java │ │ │ ├── HeadersMutator.java │ │ │ └── Mutator.java │ │ │ └── impl │ │ │ ├── BigListOfNaughtyStringsMutator.java │ │ │ ├── LowercaseExpandingBytesMutator.java │ │ │ ├── LowercaseExpandingLengthMutator.java │ │ │ ├── NullStringMutator.java │ │ │ ├── RandomAbugidasMutator.java │ │ │ ├── RandomAcceptHeaderMutator.java │ │ │ ├── RandomAlphanumericStringMutator.java │ │ │ ├── RandomContentTypeHeaderMutator.java │ │ │ ├── RandomControlCharsInFieldKeysMutator.java │ │ │ ├── RandomControlCharsMutator.java │ │ │ ├── RandomJsonMutator.java │ │ │ ├── RandomLanguageIdentifiersMutator.java │ │ │ ├── RandomLargeDecimalsMutator.java │ │ │ ├── RandomLargeIntegersMutator.java │ │ │ ├── RandomMaxValuesMutator.java │ │ │ ├── RandomMinValuesMutator.java │ │ │ ├── RandomMultiCodepointEmojisMutator.java │ │ │ ├── RandomNumberMutator.java │ │ │ ├── RandomPayloadSizeMutator.java │ │ │ ├── RandomSingleCodepointEmojisMutator.java │ │ │ ├── RandomStringMutator.java │ │ │ ├── RandomTransferEncodingHeaderMutator.java │ │ │ ├── RandomWhitespaceCharsMutator.java │ │ │ ├── RandomWhitespacesInFieldKeysMutator.java │ │ │ ├── RandomZalgoTextMutator.java │ │ │ ├── RemoveFieldMutator.java │ │ │ ├── UppercaseExpandingBytesMutator.java │ │ │ └── UppercaseExpandingLengthMutator.java │ │ ├── generator │ │ ├── Cloner.java │ │ ├── format │ │ │ ├── api │ │ │ │ ├── DataFormat.java │ │ │ │ ├── DataFormatGenerator.java │ │ │ │ ├── InvalidDataFormat.java │ │ │ │ ├── InvalidDataFormatGenerator.java │ │ │ │ ├── OpenAPIFormat.java │ │ │ │ ├── PropertySanitizer.java │ │ │ │ ├── ValidDataFormat.java │ │ │ │ ├── ValidDataFormatGenerator.java │ │ │ │ └── VoidGenerator.java │ │ │ └── impl │ │ │ │ ├── AddressGenerator.java │ │ │ │ ├── AddressLine1Generator.java │ │ │ │ ├── AddressLine2Generator.java │ │ │ │ ├── AirportCodeGenerator.java │ │ │ │ ├── BankAccountNumberGenerator.java │ │ │ │ ├── Bcp47Generator.java │ │ │ │ ├── BicGenerator.java │ │ │ │ ├── BinaryGenerator.java │ │ │ │ ├── BusinessNameGenerator.java │ │ │ │ ├── CardNumberGenerator.java │ │ │ │ ├── CardholderNameGenerator.java │ │ │ │ ├── CarrierCodeGenerator.java │ │ │ │ ├── CityGenerator.java │ │ │ │ ├── ContentTypeGenerator.java │ │ │ │ ├── CountryCodeAlpha2Generator.java │ │ │ │ ├── CountryCodeAlpha3Generator.java │ │ │ │ ├── CountryCodeGenerator.java │ │ │ │ ├── CurrencyCodeGenerator.java │ │ │ │ ├── DateGenerator.java │ │ │ │ ├── DateOfBirthGenerator.java │ │ │ │ ├── DateTimeGenerator.java │ │ │ │ ├── DepartmentGenerator.java │ │ │ │ ├── DescriptionGenerator.java │ │ │ │ ├── DurationGenerator.java │ │ │ │ ├── EmailGenerator.java │ │ │ │ ├── FirstNameGenerator.java │ │ │ │ ├── FlightCodeGenerator.java │ │ │ │ ├── FullNameGenerator.java │ │ │ │ ├── GenderGenerator.java │ │ │ │ ├── Gtin13Generator.java │ │ │ │ ├── Gtin8Generator.java │ │ │ │ ├── HostnameGenerator.java │ │ │ │ ├── IPV4Generator.java │ │ │ │ ├── IPV6Generator.java │ │ │ │ ├── IRIGenerator.java │ │ │ │ ├── IRIReferenceGenerator.java │ │ │ │ ├── ISBN10Generator.java │ │ │ │ ├── ISBN13Generator.java │ │ │ │ ├── IbanGenerator.java │ │ │ │ ├── IdnEmailGenerator.java │ │ │ │ ├── IdnHostnameGenerator.java │ │ │ │ ├── JobTitleGenerator.java │ │ │ │ ├── JsonPointerGenerator.java │ │ │ │ ├── KvPairsGenerator.java │ │ │ │ ├── LanguageGenerator.java │ │ │ │ ├── LastNameGenerator.java │ │ │ │ ├── MiddleNameGenerator.java │ │ │ │ ├── NationalityGenerator.java │ │ │ │ ├── PasswordGenerator.java │ │ │ │ ├── PeriodGenerator.java │ │ │ │ ├── PhoneNumberGenerator.java │ │ │ │ ├── PostCodeGenerator.java │ │ │ │ ├── RegexGenerator.java │ │ │ │ ├── RelativeJsonPointerGenerator.java │ │ │ │ ├── SortCodeGenerator.java │ │ │ │ ├── StateCodeGenerator.java │ │ │ │ ├── StateGenerator.java │ │ │ │ ├── TimeGenerator.java │ │ │ │ ├── TimeOfDayGenerator.java │ │ │ │ ├── TimeZoneGenerator.java │ │ │ │ ├── TimestampGenerator.java │ │ │ │ ├── URIGenerator.java │ │ │ │ ├── URIReferenceGenerator.java │ │ │ │ ├── URITemplateGenerator.java │ │ │ │ ├── UUIDGenerator.java │ │ │ │ ├── UnixtimeGenerator.java │ │ │ │ ├── UserAgentGenerator.java │ │ │ │ └── UsernameGenerator.java │ │ └── simple │ │ │ ├── NumberGenerator.java │ │ │ ├── RegexCleaner.java │ │ │ ├── RegexFlattener.java │ │ │ ├── RegexGenerator.java │ │ │ ├── StringGenerator.java │ │ │ └── UnicodeGenerator.java │ │ ├── http │ │ ├── HttpMethod.java │ │ ├── ResponseCodeFamily.java │ │ ├── ResponseCodeFamilyDynamic.java │ │ └── ResponseCodeFamilyPredefined.java │ │ ├── io │ │ ├── ServiceCaller.java │ │ ├── ServiceData.java │ │ └── util │ │ │ ├── FormEncoder.java │ │ │ ├── HttpContent.java │ │ │ └── MultipartProcessor.java │ │ ├── model │ │ ├── CatsConfiguration.java │ │ ├── CatsField.java │ │ ├── CatsHeader.java │ │ ├── CatsRequest.java │ │ ├── CatsResponse.java │ │ ├── CatsResultFactory.java │ │ ├── CatsTestCase.java │ │ ├── CatsTestCaseExecutionSummary.java │ │ ├── CatsTestCaseSummary.java │ │ ├── CatsTestReport.java │ │ ├── CustomFuzzerExecution.java │ │ ├── FuzzingConstraints.java │ │ ├── FuzzingData.java │ │ ├── NoMediaType.java │ │ ├── ProcessingError.java │ │ ├── TimeExecution.java │ │ ├── TimeExecutionDetails.java │ │ └── ann │ │ │ ├── Exclude.java │ │ │ └── ExcludeTestCaseStrategy.java │ │ ├── openapi │ │ └── OpenAPIModelGeneratorV2.java │ │ ├── report │ │ ├── ClusterCompute.java │ │ ├── ErrorSimilarityDetector.java │ │ ├── ExecutionStatisticsListener.java │ │ ├── TestCaseExporter.java │ │ ├── TestCaseExporterHtmlJs.java │ │ ├── TestCaseExporterHtmlJsCluster.java │ │ ├── TestCaseExporterHtmlOnly.java │ │ ├── TestCaseExporterJunit.java │ │ └── TestCaseListener.java │ │ ├── strategy │ │ ├── FuzzingStrategy.java │ │ ├── InsertFuzzingStrategy.java │ │ ├── NoopFuzzingStrategy.java │ │ ├── PrefixFuzzingStrategy.java │ │ ├── ReplaceFuzzingStrategy.java │ │ ├── SkipFuzzingStrategy.java │ │ └── TrailFuzzingStrategy.java │ │ └── util │ │ ├── CatsDSLWords.java │ │ ├── CatsModelUtils.java │ │ ├── CatsUtil.java │ │ ├── ConsoleUtils.java │ │ ├── DepthLimitingSerializer.java │ │ ├── FuzzingResult.java │ │ ├── JsonUtils.java │ │ ├── KeyValuePair.java │ │ ├── KeyValueSerializer.java │ │ ├── LongTypeSerializer.java │ │ ├── OffsetDatetimeTypeAdapter.java │ │ ├── OpenApiParseResult.java │ │ ├── OpenApiUtils.java │ │ ├── VersionChecker.java │ │ ├── VersionProvider.java │ │ └── WordUtils.java └── resources │ ├── LICENSE │ ├── application.properties │ ├── assets.zip │ ├── banner.txt │ ├── blns.txt │ ├── chart.js │ ├── draw_chart.js │ ├── junit_summary.mustache │ ├── pl4j.properties │ ├── ro.yml │ ├── script.js │ ├── styles-cluster.css │ ├── styles.css │ ├── summary-clusters.mustache │ ├── summary.mustache │ ├── test-case.mustache │ └── version.properties └── test ├── java └── com │ └── endava │ └── cats │ ├── archunit │ └── DependencyRulesTest.java │ ├── args │ ├── ApiArgumentsTest.java │ ├── AuthArgumentsTest.java │ ├── FilesArgumentsTest.java │ ├── FilterArgumentsTest.java │ ├── IgnoreArgumentsTest.java │ ├── MatchArgumentsTest.java │ ├── ProcessingArgumentsTest.java │ ├── StopArgumentsTest.java │ └── UserArgumentsTest.java │ ├── command │ ├── CatsCommandTest.java │ ├── ExplainCommandTest.java │ ├── GenerateCommandTest.java │ ├── InfoCommandTest.java │ ├── LintCommandTest.java │ ├── ListCommandTest.java │ ├── RandomCommandTest.java │ ├── ReplayCommandTest.java │ ├── RunCommandTest.java │ ├── StatsCommandTest.java │ ├── TemplateFuzzCommandTest.java │ └── ValidateCommandTest.java │ ├── context │ └── CatsGlobalContextTest.java │ ├── dsl │ ├── CatsDSLParserTest.java │ └── impl │ │ └── AuthScriptProviderParserTest.java │ ├── factory │ └── FuzzingDataFactoryTest.java │ ├── fuzzer │ ├── contract │ │ ├── ArrayWithoutItemsLinterTest.java │ │ ├── CollectionPaginationLinterTest.java │ │ ├── ContractFuzzerDataUtilForTest.java │ │ ├── DeleteHasBodyLinterTest.java │ │ ├── EmptyPathsLinterTest.java │ │ ├── EmptyRequestSchemaLinterTest.java │ │ ├── EmptyResponseSchemaLinterTest.java │ │ ├── GetHasBodyLinterTest.java │ │ ├── HeadersCaseLinterTest.java │ │ ├── HttpMethodConsistencyErrorLinterTest.java │ │ ├── HttpMethodConsistencyWarnLinterTest.java │ │ ├── HttpStatusCodeInRangeLinterTest.java │ │ ├── JsonObjectsCaseLinterTest.java │ │ ├── MultipleSuccessCodesLinterTest.java │ │ ├── OperationIdVerbPrefixLinterTest.java │ │ ├── PatchWithoutBodyLinterTest.java │ │ ├── PathCaseLinterTest.java │ │ ├── PathNounsLinterTest.java │ │ ├── PathPluralsLinterTest.java │ │ ├── PathTagsLinterTest.java │ │ ├── PostWithoutBodyLinterTest.java │ │ ├── PutWithoutBodyLinterTest.java │ │ ├── QueryParamsCaseLinterTest.java │ │ ├── RecommendedHttpCodesLinterTest.java │ │ ├── ResponsesWithBodiesLinterTest.java │ │ ├── SecuritySchemesLinterTest.java │ │ ├── TopLevelElementsLinterTest.java │ │ ├── TracingHeadersLinterTest.java │ │ ├── UniqueOperationIdsLinterTest.java │ │ ├── UnusedExamplesLinterTest.java │ │ ├── UnusedHeadersLinterTest.java │ │ ├── UnusedParametersLinterTest.java │ │ ├── UnusedRequestBodiesLinterTest.java │ │ ├── UnusedResponsesLinterTest.java │ │ ├── UnusedSchemasLinterTest.java │ │ ├── VersionsLinterTest.java │ │ └── XmlContentTypeLinterTest.java │ ├── executor │ │ └── FieldsIteratorExecutorTest.java │ ├── fields │ │ ├── AbugidasInStringFieldsSanitizeValidateFuzzerTest.java │ │ ├── AbugidasInStringFieldsValidateSanitizeFuzzerTest.java │ │ ├── DecimalFieldsLeftBoundaryFuzzerTest.java │ │ ├── DecimalFieldsRightBoundaryFuzzerTest.java │ │ ├── DecimalNumbersInIntegerFieldsFuzzerTest.java │ │ ├── DefaultValuesInFieldsFuzzerTest.java │ │ ├── EmptyStringsInFieldsFuzzerTest.java │ │ ├── EnumCaseVariantFieldsFuzzerTest.java │ │ ├── ExamplesFieldsFuzzerTest.java │ │ ├── ExtremeNegativeNumbersInDecimalFieldsFuzzerTest.java │ │ ├── ExtremeNegativeNumbersInIntegerFieldsFuzzerTest.java │ │ ├── ExtremePositiveNumbersInDecimalFieldsFuzzerTest.java │ │ ├── ExtremePositiveNumbersInIntegerFieldsFuzzerTest.java │ │ ├── InsertWhitespacesInFieldNamesFieldFuzzerTest.java │ │ ├── IntegerFieldsLeftBoundaryFuzzerTest.java │ │ ├── IntegerFieldsRightBoundaryFuzzerTest.java │ │ ├── InvalidReferencesFieldsFuzzerTest.java │ │ ├── InvalidValuesInEnumsFieldsFuzzerTest.java │ │ ├── IterateThroughEnumValuesFieldsFuzzerTest.java │ │ ├── LowercaseExpandingBytesInStringFieldsFuzzerTest.java │ │ ├── LowercaseExpandingLengthInStringFieldsFuzzerTest.java │ │ ├── MaxLengthExactValuesInStringFieldsFuzzerTest.java │ │ ├── MaximumExactNumbersInNumericFieldsFuzzerTest.java │ │ ├── MinGreaterThanMaxFieldsFuzzerTest.java │ │ ├── MinLengthExactValuesInStringFieldsFuzzerTest.java │ │ ├── MinimumExactNumbersInNumericFieldsFuzzerTest.java │ │ ├── NewFieldsFuzzerTest.java │ │ ├── NullValuesInFieldsFuzzerTest.java │ │ ├── OverflowArraySizeFieldsFuzzerTest.java │ │ ├── OverflowMapSizeFieldsFuzzerTest.java │ │ ├── RandomStringsInBooleanFieldsFuzzerTest.java │ │ ├── RemoveFieldsFuzzerTest.java │ │ ├── ReplaceArraysWithPrimitivesFieldsFuzzerTest.java │ │ ├── ReplaceArraysWithSimpleObjectsFieldsFuzzerTest.java │ │ ├── ReplaceObjectsWithArraysFieldsFuzzerTest.java │ │ ├── ReplaceObjectsWithPrimitivesFieldsFuzzerTest.java │ │ ├── ReplacePrimitivesWithArraysFieldsFuzzerTest.java │ │ ├── ReplacePrimitivesWithObjectsFieldsFuzzerTest.java │ │ ├── StringFieldsLeftBoundaryFuzzerTest.java │ │ ├── StringFieldsRightBoundaryFuzzerTest.java │ │ ├── StringFormatAlmostValidValuesFuzzerTest.java │ │ ├── StringFormatTotallyWrongValuesFuzzerTest.java │ │ ├── StringsInNumericFieldsFuzzerTest.java │ │ ├── TemporalLogicFieldsFuzzerTest.java │ │ ├── UppercaseExpandingBytesInStringFieldsFuzzerTest.java │ │ ├── UppercaseExpandingLengthInStringFieldsFuzzerTest.java │ │ ├── UserDictionaryFieldsFuzzerTest.java │ │ ├── VeryLargeDecimalsInNumericFieldsFuzzerTest.java │ │ ├── VeryLargeIntegersInNumericFieldsFuzzerTest.java │ │ ├── VeryLargeStringsInFieldsFuzzerTest.java │ │ ├── VeryLargeUnicodeStringsInFieldsFuzzerTest.java │ │ ├── ZalgoTextInFieldsSanitizeValidateFuzzerTest.java │ │ ├── ZalgoTextInFieldsValidateSanitizeFuzzerTest.java │ │ ├── ZeroWidthCharsInNamesFieldsFuzzerTest.java │ │ ├── ZeroWidthCharsInValuesFieldsSanitizeValidateFuzzerTest.java │ │ ├── ZeroWidthCharsInValuesFieldsValidateSanitizeFuzzerTest.java │ │ ├── base │ │ │ ├── BaseBoundaryFieldFuzzerTest.java │ │ │ ├── BaseFieldsFuzzerTest.java │ │ │ ├── ExactValuesInFieldsFuzzerTest.java │ │ │ ├── Expect4XXForRequiredBaseFieldsFuzzerTest.java │ │ │ ├── ExpectOnly2XXBaseFieldsFuzzerTest.java │ │ │ └── ExpectOnly4XXBaseFieldsFuzzerTest.java │ │ ├── leading │ │ │ ├── LeadingControlCharsInFieldsTrimValidateFuzzerTest.java │ │ │ ├── LeadingControlCharsInFieldsValidateTrimFuzzerTest.java │ │ │ ├── LeadingMultiCodePointEmojisInFieldsTrimValidateFuzzerTest.java │ │ │ ├── LeadingMultiCodePointEmojisInFieldsValidateTrimFuzzerTest.java │ │ │ ├── LeadingSingleCodePointEmojisInFieldsTrimValidateFuzzerTest.java │ │ │ ├── LeadingSingleCodePointEmojisInFieldsValidateTrimFuzzerTest.java │ │ │ ├── LeadingWhitespacesInFieldsTrimValidateFuzzerTest.java │ │ │ └── LeadingWhitespacesInFieldsValidateTrimFuzzerTest.java │ │ ├── only │ │ │ ├── OnlyControlCharsInFieldsTrimValidateFuzzerTest.java │ │ │ ├── OnlyControlCharsInFieldsValidateTrimFuzzerTest.java │ │ │ ├── OnlyMultiCodePointEmojisInFieldsTrimValidateFuzzerTest.java │ │ │ ├── OnlyMultiCodePointEmojisInFieldsValidateTrimFuzzerTest.java │ │ │ ├── OnlySingleCodePointEmojisInFieldsTrimValidateFuzzerTest.java │ │ │ ├── OnlySingleCodePointEmojisInFieldsValidateTrimFuzzerTest.java │ │ │ ├── OnlyWhitespacesInFieldsTrimValidateFuzzerTest.java │ │ │ └── OnlyWhitespacesInFieldsValidateTrimFuzzerTest.java │ │ ├── trailing │ │ │ ├── TrailingControlCharsInFieldsTrimValidateFuzzerTest.java │ │ │ ├── TrailingControlCharsInFieldsValidateTrimFuzzerTest.java │ │ │ ├── TrailingMultiCodePointEmojisInFieldsTrimValidateFuzzerTest.java │ │ │ ├── TrailingMultiCodePointEmojisInFieldsValidateTrimFuzzerTest.java │ │ │ ├── TrailingSingleCodePointEmojisInFieldsTrimValidateFuzzerTest.java │ │ │ ├── TrailingSingleCodePointEmojisInFieldsValidateTrimFuzzerTest.java │ │ │ ├── TrailingWhitespacesInFieldsTrimValidateFuzzerTest.java │ │ │ └── TrailingWhitespacesInFieldsValidateTrimFuzzerTest.java │ │ └── within │ │ │ ├── WithinControlCharsInStringFieldsSanitizeValidateFuzzerTest.java │ │ │ ├── WithinControlCharsInStringFieldsValidateSanitizeFuzzerTest.java │ │ │ ├── WithinMultiCodePointEmojisInStringFieldsTrimValidateFuzzerTest.java │ │ │ ├── WithinMultiCodePointEmojisInStringFieldsValidateTrimFuzzerTest.java │ │ │ ├── WithinSingleCodePointEmojisInStringFieldsTrimValidateFuzzerTest.java │ │ │ └── WithinSingleCodePointEmojisInStringFieldsValidateTrimFuzzerTest.java │ ├── headers │ │ ├── AbugidasInHeadersFuzzerTest.java │ │ ├── AcceptLanguageHeadersFuzzerTest.java │ │ ├── CRLFHeadersFuzzerTest.java │ │ ├── CheckSecurityHeadersFuzzerTest.java │ │ ├── DummyAcceptHeadersFuzzerTest.java │ │ ├── DummyContentLengthHeadersFuzzerTest.java │ │ ├── DummyContentTypeHeadersFuzzerTest.java │ │ ├── DummyTransferEncodingHeadersFuzzerTest.java │ │ ├── DuplicateHeadersFuzzerTest.java │ │ ├── EmptyStringsInHeadersFuzzerTest.java │ │ ├── ExtraHeadersFuzzerTest.java │ │ ├── InvalidContentLengthHeadersFuzzerTest.java │ │ ├── LargeNumberOfRandomAlphanumericHeadersFuzzerTest.java │ │ ├── LargeNumberOfRandomHeadersFuzzerTest.java │ │ ├── RemoveHeadersFuzzerTest.java │ │ ├── ResponseHeadersMatchContractHeadersFuzzerTest.java │ │ ├── UnsupportedAcceptHeadersFuzzerTest.java │ │ ├── UnsupportedContentTypesHeadersFuzzerTest.java │ │ ├── UserDictionaryHeadersFuzzerTest.java │ │ ├── VeryLargeStringsInHeadersFuzzerTest.java │ │ ├── VeryLargeUnicodeStringsInHeadersFuzzerTest.java │ │ ├── ZalgoTextInHeadersFuzzerTest.java │ │ ├── ZeroWidthCharsInNamesHeadersFuzzerTest.java │ │ ├── ZeroWidthCharsInValuesHeadersFuzzerTest.java │ │ ├── base │ │ │ └── BaseHeadersFuzzerTest.java │ │ ├── leading │ │ │ ├── LeadingControlCharsInHeadersFuzzerTest.java │ │ │ ├── LeadingMultiCodePointEmojisInHeadersFuzzerTest.java │ │ │ ├── LeadingSingleCodePointEmojisInHeadersFuzzerTest.java │ │ │ ├── LeadingSpacesInHeadersFuzzerTest.java │ │ │ └── LeadingWhitespacesInHeadersFuzzerTest.java │ │ ├── only │ │ │ ├── OnlyControlCharsInHeadersFuzzerTest.java │ │ │ ├── OnlyMultiCodePointEmojisInHeadersFuzzerTest.java │ │ │ ├── OnlySingleCodePointEmojisInHeadersFuzzerTest.java │ │ │ ├── OnlySpacesInHeadersFuzzerTest.java │ │ │ └── OnlyWhitespacesInHeadersFuzzerTest.java │ │ └── trailing │ │ │ ├── TrailingControlCharsInHeadersFuzzerTest.java │ │ │ ├── TrailingMultiCodePointEmojisHeadersFuzzerTest.java │ │ │ ├── TrailingSingleCodePointEmojisHeadersFuzzerTest.java │ │ │ ├── TrailingSpacesInHeadersFuzzerTest.java │ │ │ └── TrailingWhitespacesInHeadersFuzzerTest.java │ ├── http │ │ ├── BypassAuthenticationFuzzerTest.java │ │ ├── CheckDeletedResourcesNotAvailableFuzzerTest.java │ │ ├── CustomHttpMethodsFuzzerTest.java │ │ ├── DummyRequestFuzzerTest.java │ │ ├── EmptyBodyFuzzerTest.java │ │ ├── EmptyJsonArrayBodyFuzzerTest.java │ │ ├── EmptyJsonBodyFuzzerTest.java │ │ ├── HappyPathFuzzerTest.java │ │ ├── HttpMethodsFuzzerTest.java │ │ ├── InsertRandomValuesInBodyFuzzerTest.java │ │ ├── MalformedJsonFuzzerTest.java │ │ ├── NonRestHttpMethodsFuzzerTest.java │ │ ├── NullBodyFuzzerTest.java │ │ ├── NullUnicodeBodyFuzzerTest.java │ │ ├── NullUnicodeSymbolBodyFuzzerTest.java │ │ ├── RandomDummyInvalidJsonBodyFuzzerTest.java │ │ ├── RandomNegativeDecimalBodyFuzzerTest.java │ │ ├── RandomNegativeIntegerBodyFuzzerTest.java │ │ ├── RandomPositiveDecimalBodyFuzzerTest.java │ │ ├── RandomPositiveIntegerBodyFuzzerTest.java │ │ ├── RandomResourcesFuzzerTest.java │ │ ├── RandomStringBodyFuzzerTest.java │ │ ├── RandomUnicodeBodyFuzzerTest.java │ │ ├── ZeroDecimalBodyFuzzerTest.java │ │ └── ZeroIntegerBodyFuzzerTest.java │ └── special │ │ ├── FunctionalFuzzerTest.java │ │ ├── RandomFuzzerTest.java │ │ ├── SecurityFuzzerTest.java │ │ ├── TemplateFuzzerTest.java │ │ └── mutators │ │ └── StringMutationUtilsTest.java │ ├── generator │ ├── format │ │ ├── api │ │ │ ├── DataFormatTest.java │ │ │ ├── InvalidDataFormatTest.java │ │ │ ├── ValidDataFormatTest.java │ │ │ └── VoidGeneratorTest.java │ │ └── impl │ │ │ ├── AddressGeneratorTest.java │ │ │ ├── AddressLine1GeneratorTest.java │ │ │ ├── AddressLine2GeneratorTest.java │ │ │ ├── AirportCodeGeneratorTest.java │ │ │ ├── BankAccountNumberGeneratorTest.java │ │ │ ├── Bcp47GeneratorTest.java │ │ │ ├── BicGeneratorTest.java │ │ │ ├── BinaryGeneratorTest.java │ │ │ ├── BusinessNameGeneratorTest.java │ │ │ ├── CardHolderNameGeneratorTest.java │ │ │ ├── CardNumberGeneratorTest.java │ │ │ ├── CarrierCodeGeneratorTest.java │ │ │ ├── CityGeneratorTest.java │ │ │ ├── ContentTypeGeneratorTest.java │ │ │ ├── CountryCodeAlpha2GeneratorTest.java │ │ │ ├── CountryCodeAlpha3GeneratorTest.java │ │ │ ├── CountryCodeGeneratorTest.java │ │ │ ├── CurrencyCodeGeneratorTest.java │ │ │ ├── DateGeneratorTest.java │ │ │ ├── DateOfBirthGeneratorTest.java │ │ │ ├── DateTimeGeneratorTest.java │ │ │ ├── DepartmentGeneratorTest.java │ │ │ ├── DescriptionGeneratorTest.java │ │ │ ├── DurationGeneratorTest.java │ │ │ ├── EmailGeneratorTest.java │ │ │ ├── FirstNameGeneratorTest.java │ │ │ ├── FlightCodeGeneratorTest.java │ │ │ ├── FullNameGeneratorTest.java │ │ │ ├── GenderGeneratorTest.java │ │ │ ├── Gtin13GeneratorTest.java │ │ │ ├── Gtin8GeneratorTest.java │ │ │ ├── HostnameGeneratorTest.java │ │ │ ├── IPV4GeneratorTest.java │ │ │ ├── IPV6GeneratorTest.java │ │ │ ├── IRIGeneratorTest.java │ │ │ ├── IRIReferenceGeneratorTest.java │ │ │ ├── ISBN10GeneratorTest.java │ │ │ ├── ISBN13GeneratorTest.java │ │ │ ├── IbanGeneratorTest.java │ │ │ ├── IdnEmailGeneratorTest.java │ │ │ ├── IdnHostnameGeneratorTest.java │ │ │ ├── JobTitleGeneratorTest.java │ │ │ ├── JsonPointerGeneratorTest.java │ │ │ ├── KvPairsGeneratorTest.java │ │ │ ├── LanguageGeneratorTest.java │ │ │ ├── LastNameGeneratorTest.java │ │ │ ├── MiddleNameGeneratorTest.java │ │ │ ├── NationalityGeneratorTest.java │ │ │ ├── PasswordGeneratorTest.java │ │ │ ├── PeriodGeneratorTest.java │ │ │ ├── PhoneNumberGeneratorTest.java │ │ │ ├── PostCodeGeneratorTest.java │ │ │ ├── RegexGeneratorTest.java │ │ │ ├── RelativeJsonPointerGeneratorTest.java │ │ │ ├── SortCodeGeneratorTest.java │ │ │ ├── StateCodeGeneratorTest.java │ │ │ ├── StateGeneratorTest.java │ │ │ ├── TimeGeneratorTest.java │ │ │ ├── TimeOfDayGeneratorTest.java │ │ │ ├── TimeZoneGeneratorTest.java │ │ │ ├── TimestampGeneratorTest.java │ │ │ ├── URIGeneratorTest.java │ │ │ ├── URIReferenceGeneratorTest.java │ │ │ ├── URITemplateGeneratorTest.java │ │ │ ├── UUIDGeneratorTest.java │ │ │ ├── UnixtimeGeneratorTest.java │ │ │ ├── UserAgentGeneratorTest.java │ │ │ └── UsernameGeneratorTest.java │ └── simple │ │ ├── NumberGeneratorTest.java │ │ ├── RegexGeneratorTest.java │ │ ├── StringGeneratorTest.java │ │ └── UnicodeGeneratorTest.java │ ├── http │ └── ResponseCodeFamilyPredefinedTest.java │ ├── io │ └── ServiceCallerTest.java │ ├── model │ ├── CatsHeaderTest.java │ ├── CatsResponseTest.java │ ├── CatsTestCaseSummaryTest.java │ ├── CatsTestCaseTest.java │ ├── FunctionalFuzzerExecutionTest.java │ ├── FuzzingConstraintsTest.java │ ├── FuzzingDataTest.java │ ├── NoMediaTypeTest.java │ ├── ProcessingErrorTest.java │ └── ann │ │ └── ExcludeTestCaseStrategyTest.java │ ├── openapi │ └── OpenAPIModelGeneratorV2Test.java │ ├── report │ ├── ClusterComputeTest.java │ ├── ErrorSimilarityDetectorTest.java │ ├── ExecutionStatisticsListenerTest.java │ └── TestCaseListenerTest.java │ ├── strategy │ ├── FuzzingStrategyTest.java │ ├── NoopFuzzingStrategyTest.java │ ├── PrefixFuzzingStrategyTest.java │ ├── ReplaceFuzzingStrategyTest.java │ ├── SkipFuzzingStrategyTest.java │ └── TrailFuzzingStrategyTest.java │ └── util │ ├── CatsModeLUtilsTest.java │ ├── CatsUtilTest.java │ ├── DepthLimitingSerializerTest.java │ ├── GlobalLoggingExtension.java │ ├── JsonUtilsTest.java │ ├── KeyValueSerializerTest.java │ ├── LongTypeSerializerTest.java │ ├── OffsetDatetimeTypeAdapterTest.java │ ├── OpenApiParseResultTest.java │ ├── OpenApiUtilsTest.java │ ├── VersionCheckerTest.java │ └── WordUtilsTest.java └── resources ├── 1password.yaml ├── META-INF └── services │ └── io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback ├── Test12.json ├── allof-with-required-for-both-schemas.yml ├── allof-with-required-in-root.yml ├── application.properties ├── baserow.yaml ├── cats.jks ├── consistent-api.yml ├── contract-incomplete-contact.yml ├── contract-incomplete-tags.yml ├── contract-missing-info.yml ├── contract-missing-servers.yml ├── contract-missing-tags.yml ├── contract-no-path-tags.yml ├── contract-no-security.yml ├── contract-path-tags-mismatch.yml ├── contract-security-mismatch-schemes.yml ├── data.json ├── dict.txt ├── digitalocean.yaml ├── discovery.yaml ├── duplicate-operationids.yml ├── empty-paths.yml ├── empty.yml ├── enode.yaml ├── error_leaks.txt ├── functionalFuzzer-additional.yml ├── functionalFuzzer-array-iterate.yml ├── functionalFuzzer-array-replace.yml ├── functionalFuzzer-http-method.yml ├── functionalFuzzer-multiple-rp.yml ├── functionalFuzzer-no-resp-code.yml ├── functionalFuzzer-req-verify.yml ├── functionalFuzzer-resp-code-family-verify.yml ├── functionalFuzzer-resp-code-family.yml ├── functionalFuzzer-resp-code-verify.yml ├── functionalFuzzer-verify-not-set.yml ├── functionalFuzzer-verify.yml ├── functionalFuzzer.yml ├── fuzzConfig.properties ├── getresp.yaml ├── griffin.yaml ├── gusto.yaml ├── headers.yml ├── inconsistent-api-2.yml ├── inconsistent-api.yml ├── issue117.json ├── issue127.json ├── issue144.yml ├── issue146.yml ├── issue66.yml ├── issue66_2.yml ├── issue77.json ├── issue86.json ├── issue94.json ├── issue98.json ├── issue_69.yml ├── keatext.yaml ├── mutators ├── first.yml ├── second.yml └── third.yml ├── no-paths.yml ├── nocodb.yaml ├── nswag_gen_oneof.json ├── oneOf_with_base_class.yml ├── oneOf_with_null_additional.yml ├── openapi.yml ├── paths.order ├── petstore-deprecated-tags.yml ├── petstore-empty.yml ├── petstore-examples.yml ├── petstore-invalid-content.yml ├── petstore-no-schema.yml ├── petstore-nonjson.yml ├── petstore-readonly.yml ├── petstore.yml ├── petstore31.yaml ├── petstore_empty_body.json ├── presalytics.yml ├── prolific.yaml ├── queryParams.yml ├── queryParamsEmpty.yml ├── refFields.yml ├── refFields_with_all.yml ├── securityFuzzer-all.yml ├── securityFuzzer-allPaths.yml ├── securityFuzzer-arrays.yml ├── securityFuzzer-fieldTypes-http-body.yml ├── securityFuzzer-fieldTypes.yml ├── securityFuzzer-invalidStrings.yml ├── securityFuzzer-missing.yml ├── securityFuzzer.yml ├── sellsy.yaml ├── shippo.yaml ├── test.yml ├── token.yml ├── verbs.properties └── wrong_headers.yml /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created 2 | # For more information see: https://github.com/actions/setup-java#apache-maven-with-a-settings-path 3 | 4 | name: Maven Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up JDK 1.8 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 1.8 21 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml 22 | settings-path: ${{ github.workspace }} # location for the settings.xml file 23 | 24 | - name: Build with Maven 25 | run: | 26 | mvn -B clean --file pom.xml 27 | mvn -B package --file pom.xml 28 | 29 | - name: Publish to GitHub Packages Apache Maven 30 | run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml 31 | env: 32 | GITHUB_TOKEN: ${{ github.token }} 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | target 4 | test-report 5 | .DS_Store 6 | *.jar 7 | *.swp 8 | *.csv 9 | *.cer 10 | *.key 11 | cats-report 12 | log 13 | examples 14 | rules 15 | __pycache__ 16 | pom_native.xml 17 | cats*.tar.gz 18 | refData_custom.yml 19 | referenceFields_replaced.yml 20 | -------------------------------------------------------------------------------- /.mvn/jvm.config: -------------------------------------------------------------------------------- 1 | --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED 2 | --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED 3 | --add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED 4 | --add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED 5 | --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 6 | --add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED 7 | --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED 8 | --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED 9 | --add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED 10 | --add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /files/errorLeaks.txt: -------------------------------------------------------------------------------- 1 | json: cannot unmarshal 2 | fatal error: stack overflow -------------------------------------------------------------------------------- /files/functionalFuzzer.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test1: 3 | pet#id: 4 | - stay 5 | - at 6 | - home 7 | httpMethod: POST 8 | /go: 9 | test1: 10 | homeId: 11 | - 123 12 | - 124 13 | - 134 14 | home#country: "mumu" 15 | httpMethod: POST 16 | additionalProperties: 17 | element: "metadata" 18 | mapValues: 19 | test: "bubu" 20 | anotherTest: "juju" 21 | expectedResponseCode: 200 22 | oneOfSelection: 23 | pet#type: "Dog" 24 | output: 25 | - homeId: home#id 26 | verify: 27 | pet#name: "Baby" 28 | pet#id: "[0-9]+" 29 | test2: 30 | homeId: 31 | - 123 32 | - 124 33 | home#country: ${homeId} 34 | httpMethod: POST 35 | expectedResponseCode: 200 -------------------------------------------------------------------------------- /files/fuzzConfig.properties: -------------------------------------------------------------------------------- 1 | DummyAcceptHeaders.expectedResponseCode=403 2 | 3 | -------------------------------------------------------------------------------- /files/headers.yml: -------------------------------------------------------------------------------- 1 | all: 2 | Authorization: Bearer jwt 3 | TraceId: 1dd361e3-c35e-4439-a67c-47a9ba8d098b 4 | /pets: 5 | API-Key: 123 -------------------------------------------------------------------------------- /files/mutators/first.yml: -------------------------------------------------------------------------------- 1 | name: xss mutator 2 | type: replace 3 | values: 4 | - "\74k 4 | 5 | <script>alert('123');</script> 6 | 7 | 8 | "> 9 | '> 10 | > 11 | 12 | < / script >< script >alert(123)< / script > 13 | onfocus=JaVaSCript:alert(123) autofocus 14 | " onfocus=JaVaSCript:alert(123) autofocus 15 | ' onfocus=JaVaSCript:alert(123) autofocus 16 | <script>alert(123)</script> 17 | ript>alert(123)ript> 18 | 19 | # Comment 20 | --> 21 | ";alert(123);t=" 22 | ';alert(123);t=' 23 | JavaSCript:alert(123) 24 | ;alert(123); 25 | 26 | src=JaVaSCript:prompt(132) 27 | "> { 12 | 13 | @Override 14 | public int compareTo(@NotNull MutatorEntry o) { 15 | return this.name().compareTo(o.name()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/command/model/PathDetailsEntry.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.command.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | /** 10 | * Represents details about a path, including the path itself and a list of operation details. 11 | */ 12 | @Builder 13 | @Getter 14 | public class PathDetailsEntry { 15 | private String path; 16 | private List operations; 17 | 18 | /** 19 | * Represents details about an operation, including its operation ID, HTTP method, 20 | * responses, query parameters, and headers. 21 | */ 22 | @Builder 23 | @Getter 24 | public static class OperationDetails { 25 | private String operationId; 26 | private String httpMethod; 27 | private Set responses; 28 | private Set queryParams; 29 | private Set headers; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/command/model/PathListEntry.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.command.model; 2 | 3 | import com.endava.cats.http.HttpMethod; 4 | import lombok.Builder; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.Getter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Represents an entry in a path list, including the number of paths, number of operations, and a list of path details. 12 | */ 13 | @Builder 14 | @Getter 15 | public class PathListEntry { 16 | private int numberOfPaths; 17 | private int numberOfOperations; 18 | private List pathDetailsList; 19 | 20 | /** 21 | * Represents details about a path, including the HTTP methods and path itself. 22 | */ 23 | @Builder 24 | @Getter 25 | @EqualsAndHashCode(of = "path") 26 | public static class PathDetails implements Comparable { 27 | private List methods; 28 | private String path; 29 | 30 | @Override 31 | public int compareTo(PathListEntry.PathDetails o) { 32 | return this.getPath().compareTo(o.getPath()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/command/model/ValidContractEntry.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.command.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Entity to hold OpenAPI spec validation information. 7 | * 8 | * @param valid if the OpenAPI contract is valid or not 9 | * @param version the OpenAPI version 10 | * @param reasons if spec is not valid, this will hold the reasons why 11 | */ 12 | public record ValidContractEntry(boolean valid, String version, List reasons) { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/dsl/api/Parser.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.dsl.api; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * A {@code Parser} is used to interpret different types of expressions found in CATS configuration files. These can range from 7 | * environment variables to dynamic expression (like Spring EL). 8 | */ 9 | public interface Parser { 10 | /** 11 | * Holds the name of the request object. 12 | */ 13 | String REQUEST = "request"; 14 | /** 15 | * Holds the name for the response object. 16 | */ 17 | String RESPONSE = "response"; 18 | /** 19 | * Holds the name for the auth script name variable. 20 | */ 21 | String AUTH_SCRIPT = "auth_script"; 22 | /** 23 | * Holds the name for the auth script refresh interval variable. 24 | */ 25 | String AUTH_REFRESH = "auth_refresh"; 26 | 27 | /** 28 | * Parses the given expression within the given context and returns the result. 29 | * 30 | * @param expression the expression that needs to be extracted from the context 31 | * @param context a given context; can be a JSON payload, a Map of data, etc 32 | * @return the result of the parsing within the given context 33 | */ 34 | String parse(String expression, Map context); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/dsl/impl/EnvVariableParser.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.dsl.impl; 2 | 3 | import com.endava.cats.dsl.api.Parser; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * Parser used to retrieve environment variables. The variables are in the {@code $$variable} format. 9 | */ 10 | public class EnvVariableParser implements Parser { 11 | private static final String ENV_VARIABLE_NOT_FOUND = "not_found_"; 12 | 13 | @Override 14 | public String parse(String expression, Map context) { 15 | String result = System.getenv(expression.replace("$", "")); 16 | return result == null ? ENV_VARIABLE_NOT_FOUND + expression : result; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/dsl/impl/NoOpParser.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.dsl.impl; 2 | 3 | import com.endava.cats.dsl.api.Parser; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * No operation parser. Returns the same input expression. 9 | */ 10 | public class NoOpParser implements Parser { 11 | @Override 12 | public String parse(String expression, Map context) { 13 | return expression; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/exception/CatsException.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.exception; 2 | 3 | /** 4 | * A custom runtime exception for Cats-related exceptions, extending {@link RuntimeException}. 5 | */ 6 | public class CatsException extends RuntimeException { 7 | 8 | /** 9 | * Constructs a new {@code CatsException} with the specified cause. 10 | * 11 | * @param e the cause of the exception 12 | */ 13 | public CatsException(Exception e) { 14 | super(e); 15 | } 16 | 17 | /** 18 | * Constructs a new {@code CatsException} with the specified detail message and cause. 19 | * 20 | * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) 21 | * @param e the cause of the exception 22 | */ 23 | public CatsException(String message, Exception e) { 24 | super(message, e); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/DeleteHasBodyLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.fuzzer.contract.base.AbstractRequestWithoutBodyLinter; 5 | import com.endava.cats.http.HttpMethod; 6 | import com.endava.cats.report.TestCaseListener; 7 | import jakarta.inject.Singleton; 8 | 9 | @Linter 10 | @Singleton 11 | public class DeleteHasBodyLinter extends AbstractRequestWithoutBodyLinter { 12 | /** 13 | * Creates a new instance of subclasses. 14 | * 15 | * @param tcl the test case listener 16 | */ 17 | protected DeleteHasBodyLinter(TestCaseListener tcl) { 18 | super(tcl); 19 | } 20 | 21 | @Override 22 | protected HttpMethod targetHttpMethod() { 23 | return HttpMethod.DELETE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/GetHasBodyLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | 4 | import com.endava.cats.annotations.Linter; 5 | import com.endava.cats.fuzzer.contract.base.AbstractRequestWithoutBodyLinter; 6 | import com.endava.cats.http.HttpMethod; 7 | import com.endava.cats.report.TestCaseListener; 8 | import jakarta.inject.Singleton; 9 | 10 | @Singleton 11 | @Linter 12 | public class GetHasBodyLinter extends AbstractRequestWithoutBodyLinter { 13 | 14 | /** 15 | * Creates a new instance of subclasses. 16 | * 17 | * @param tcl the test case listener 18 | */ 19 | protected GetHasBodyLinter(TestCaseListener tcl) { 20 | super(tcl); 21 | } 22 | 23 | @Override 24 | protected HttpMethod targetHttpMethod() { 25 | return HttpMethod.GET; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/HeadHasBodyLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.fuzzer.contract.base.AbstractRequestWithoutBodyLinter; 5 | import com.endava.cats.http.HttpMethod; 6 | import com.endava.cats.report.TestCaseListener; 7 | import jakarta.inject.Singleton; 8 | 9 | @Linter 10 | @Singleton 11 | public class HeadHasBodyLinter extends AbstractRequestWithoutBodyLinter { 12 | /** 13 | * Creates a new instance of subclasses. 14 | * 15 | * @param tcl the test case listener 16 | */ 17 | protected HeadHasBodyLinter(TestCaseListener tcl) { 18 | super(tcl); 19 | } 20 | 21 | @Override 22 | protected HttpMethod targetHttpMethod() { 23 | return HttpMethod.HEAD; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/PatchWithoutBodyLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.fuzzer.contract.base.AbstractRequestBodyLinter; 5 | import com.endava.cats.http.HttpMethod; 6 | import com.endava.cats.report.TestCaseListener; 7 | import jakarta.inject.Singleton; 8 | 9 | @Linter 10 | @Singleton 11 | public class PatchWithoutBodyLinter extends AbstractRequestBodyLinter { 12 | protected PatchWithoutBodyLinter(TestCaseListener tcl) { 13 | super(tcl); 14 | } 15 | 16 | @Override 17 | protected HttpMethod targetHttpMethod() { 18 | return HttpMethod.PATCH; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/PostWithoutBodyLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.fuzzer.contract.base.AbstractRequestBodyLinter; 5 | import com.endava.cats.http.HttpMethod; 6 | import com.endava.cats.report.TestCaseListener; 7 | import jakarta.inject.Singleton; 8 | 9 | @Linter 10 | @Singleton 11 | public class PostWithoutBodyLinter extends AbstractRequestBodyLinter { 12 | protected PostWithoutBodyLinter(TestCaseListener tcl) { 13 | super(tcl); 14 | } 15 | 16 | @Override 17 | protected HttpMethod targetHttpMethod() { 18 | return HttpMethod.POST; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/PutWithoutBodyLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.fuzzer.contract.base.AbstractRequestBodyLinter; 5 | import com.endava.cats.http.HttpMethod; 6 | import com.endava.cats.report.TestCaseListener; 7 | import jakarta.inject.Singleton; 8 | 9 | @Linter 10 | @Singleton 11 | public class PutWithoutBodyLinter extends AbstractRequestBodyLinter { 12 | 13 | public PutWithoutBodyLinter(TestCaseListener testCaseListener) { 14 | super(testCaseListener); 15 | } 16 | 17 | @Override 18 | protected HttpMethod targetHttpMethod() { 19 | return HttpMethod.PUT; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/UnusedExamplesLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.context.CatsGlobalContext; 5 | import com.endava.cats.fuzzer.contract.base.AbstractUnusedElementsLinter; 6 | import com.endava.cats.report.TestCaseListener; 7 | import io.swagger.v3.oas.models.Components; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.Map; 11 | import java.util.function.Function; 12 | 13 | @Linter 14 | @Singleton 15 | public class UnusedExamplesLinter extends AbstractUnusedElementsLinter { 16 | public UnusedExamplesLinter(TestCaseListener tcl, CatsGlobalContext catsGlobalContext) { 17 | super(tcl, catsGlobalContext); 18 | } 19 | 20 | @Override 21 | protected String getElementType() { 22 | return "examples"; 23 | } 24 | 25 | @Override 26 | protected Function> getElementsFunction() { 27 | return Components::getExamples; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/UnusedHeadersLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.context.CatsGlobalContext; 5 | import com.endava.cats.fuzzer.contract.base.AbstractUnusedElementsLinter; 6 | import com.endava.cats.report.TestCaseListener; 7 | import io.swagger.v3.oas.models.Components; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.Map; 11 | import java.util.function.Function; 12 | 13 | @Linter 14 | @Singleton 15 | public class UnusedHeadersLinter extends AbstractUnusedElementsLinter { 16 | public UnusedHeadersLinter(TestCaseListener tcl, CatsGlobalContext catsGlobalContext) { 17 | super(tcl, catsGlobalContext); 18 | } 19 | 20 | @Override 21 | protected String getElementType() { 22 | return "headers"; 23 | } 24 | 25 | @Override 26 | protected Function> getElementsFunction() { 27 | return Components::getHeaders; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/UnusedParametersLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.context.CatsGlobalContext; 5 | import com.endava.cats.fuzzer.contract.base.AbstractUnusedElementsLinter; 6 | import com.endava.cats.report.TestCaseListener; 7 | import io.swagger.v3.oas.models.Components; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.Map; 11 | import java.util.function.Function; 12 | 13 | @Linter 14 | @Singleton 15 | public class UnusedParametersLinter extends AbstractUnusedElementsLinter { 16 | public UnusedParametersLinter(TestCaseListener tcl, CatsGlobalContext catsGlobalContext) { 17 | super(tcl, catsGlobalContext); 18 | } 19 | 20 | @Override 21 | protected String getElementType() { 22 | return "parameters"; 23 | } 24 | 25 | @Override 26 | protected Function> getElementsFunction() { 27 | return Components::getParameters; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/UnusedRequestBodiesLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.context.CatsGlobalContext; 5 | import com.endava.cats.fuzzer.contract.base.AbstractUnusedElementsLinter; 6 | import com.endava.cats.report.TestCaseListener; 7 | import io.swagger.v3.oas.models.Components; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.Map; 11 | import java.util.function.Function; 12 | 13 | @Linter 14 | @Singleton 15 | public class UnusedRequestBodiesLinter extends AbstractUnusedElementsLinter { 16 | public UnusedRequestBodiesLinter(TestCaseListener tcl, CatsGlobalContext catsGlobalContext) { 17 | super(tcl, catsGlobalContext); 18 | } 19 | 20 | @Override 21 | protected String getElementType() { 22 | return "requestBodies"; 23 | } 24 | 25 | @Override 26 | protected Function> getElementsFunction() { 27 | return Components::getRequestBodies; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/UnusedResponsesLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.context.CatsGlobalContext; 5 | import com.endava.cats.fuzzer.contract.base.AbstractUnusedElementsLinter; 6 | import com.endava.cats.report.TestCaseListener; 7 | import io.swagger.v3.oas.models.Components; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.Map; 11 | import java.util.function.Function; 12 | 13 | @Linter 14 | @Singleton 15 | public class UnusedResponsesLinter extends AbstractUnusedElementsLinter { 16 | 17 | public UnusedResponsesLinter(TestCaseListener tcl, CatsGlobalContext catsGlobalContext) { 18 | super(tcl, catsGlobalContext); 19 | } 20 | 21 | @Override 22 | protected String getElementType() { 23 | return "responses"; 24 | } 25 | 26 | @Override 27 | protected Function> getElementsFunction() { 28 | return Components::getResponses; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/contract/UnusedSchemasLinter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.contract; 2 | 3 | import com.endava.cats.annotations.Linter; 4 | import com.endava.cats.context.CatsGlobalContext; 5 | import com.endava.cats.fuzzer.contract.base.AbstractUnusedElementsLinter; 6 | import com.endava.cats.report.TestCaseListener; 7 | import io.swagger.v3.oas.models.Components; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.Map; 11 | import java.util.function.Function; 12 | 13 | @Linter 14 | @Singleton 15 | public class UnusedSchemasLinter extends AbstractUnusedElementsLinter { 16 | public UnusedSchemasLinter(TestCaseListener tcl, CatsGlobalContext catsGlobalContext) { 17 | super(tcl, catsGlobalContext); 18 | } 19 | 20 | @Override 21 | protected String getElementType() { 22 | return "schemas"; 23 | } 24 | 25 | @Override 26 | protected Function> getElementsFunction() { 27 | return Components::getSchemas; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/fields/base/CustomFuzzerBase.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.fields.base; 2 | 3 | import com.endava.cats.fuzzer.api.Fuzzer; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Marker interface for fuzzers using CATS dsl. 9 | */ 10 | public interface CustomFuzzerBase extends Fuzzer { 11 | 12 | /** 13 | * Retrieves a list of reserved words. 14 | * 15 | * @return A {@link List} of {@link String} representing reserved words. 16 | */ 17 | List requiredKeywords(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/fields/only/InvisibleCharsOnlyValidateTrimFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.fields.only; 2 | 3 | import com.endava.cats.args.FilesArguments; 4 | import com.endava.cats.args.FilterArguments; 5 | import com.endava.cats.http.ResponseCodeFamily; 6 | import com.endava.cats.http.ResponseCodeFamilyPredefined; 7 | import com.endava.cats.io.ServiceCaller; 8 | import com.endava.cats.report.TestCaseListener; 9 | 10 | /** 11 | * Base class for fuzzers sending only invisible chars in fields. 12 | */ 13 | public abstract class InvisibleCharsOnlyValidateTrimFuzzer extends InvisibleCharsOnlyTrimValidateFuzzer { 14 | 15 | /** 16 | * Constructor for initializing common dependencies for fuzzing fields with invisible chars. 17 | * 18 | * @param sc the service caller 19 | * @param lr the test case listener 20 | * @param cp files arguments 21 | * @param fa filter arguments 22 | */ 23 | protected InvisibleCharsOnlyValidateTrimFuzzer(ServiceCaller sc, TestCaseListener lr, FilesArguments cp, FilterArguments fa) { 24 | super(sc, lr, cp, fa); 25 | } 26 | 27 | @Override 28 | public ResponseCodeFamily getExpectedHttpCodeWhenOptionalFieldsAreFuzzed() { 29 | return ResponseCodeFamilyPredefined.FOURXX; 30 | } 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/headers/UnsupportedAcceptHeadersFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.headers; 2 | 3 | import com.endava.cats.annotations.HeaderFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.CatsHeader; 6 | import com.endava.cats.model.FuzzingData; 7 | import com.google.common.net.HttpHeaders; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.Collection; 11 | import java.util.List; 12 | import java.util.Set; 13 | 14 | /** 15 | * Adds unsupported Accept headers. 16 | */ 17 | @Singleton 18 | @HeaderFuzzer 19 | public class UnsupportedAcceptHeadersFuzzer extends DummyAcceptHeadersFuzzer { 20 | 21 | /** 22 | * Creates a new instance. 23 | * 24 | * @param simpleExecutor executor used to run the fuzz logic 25 | */ 26 | public UnsupportedAcceptHeadersFuzzer(SimpleExecutor simpleExecutor) { 27 | super(simpleExecutor); 28 | } 29 | 30 | @Override 31 | public String typeOfHeader() { 32 | return "unsupported"; 33 | } 34 | 35 | @Override 36 | public List> getHeaders(FuzzingData data) { 37 | return filterHeaders(data, HttpHeaders.ACCEPT, data.getResponseContentTypes().values(). 38 | stream().flatMap(Collection::stream).toList()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/DummyRequestFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends a dummy request. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class DummyRequestFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | static final String DUMMY_JSON = "{\"cats\":\"cats\"}"; 16 | 17 | /** 18 | * Creates a new DummyRequestFuzzer instance 19 | * 20 | * @param executor the executor 21 | */ 22 | @Inject 23 | public DummyRequestFuzzer(SimpleExecutor executor) { 24 | super(executor); 25 | } 26 | 27 | @Override 28 | protected String getScenario() { 29 | return "Send a dummy JSON"; 30 | } 31 | 32 | @Override 33 | protected String getPayload(FuzzingData data) { 34 | return DUMMY_JSON; 35 | } 36 | 37 | @Override 38 | public String description() { 39 | return "send a dummy json request {'cats': 'cats'}"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/EmptyBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends an empty body. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class EmptyBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new EmptyBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public EmptyBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getScenario() { 28 | return "Send a request with an empty string body"; 29 | } 30 | 31 | @Override 32 | protected String getPayload(FuzzingData data) { 33 | return ""; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a empty string body"; 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/EmptyJsonArrayBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends an empty json array body. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class EmptyJsonArrayBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new EmptyJsonArrayBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public EmptyJsonArrayBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getScenario() { 28 | return "Send a request with an empty json array body"; 29 | } 30 | 31 | @Override 32 | protected String getPayload(FuzzingData data) { 33 | return "[]"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a empty json array body"; 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/EmptyJsonBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that send am empty json body. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class EmptyJsonBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new EmptyJsonBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public EmptyJsonBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getScenario() { 28 | return "Send a request with an empty json body"; 29 | } 30 | 31 | @Override 32 | protected String getPayload(FuzzingData data) { 33 | return "{}"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a empty json body"; 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/MalformedJsonFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends a malformed JSON request. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class MalformedJsonFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new MalformedJsonFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public MalformedJsonFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getScenario() { 28 | return "Send a malformed JSON which has the string 'bla' at the end"; 29 | } 30 | 31 | @Override 32 | protected String getPayload(FuzzingData data) { 33 | return data.getPayload() + "bla"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a malformed json request which has the String 'bla' at the end"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/NullBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that will send a null request. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class NullBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new NullBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public NullBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return "null"; 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with a NULL body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a NULL body"; 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/NullUnicodeBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends the null unicode value as body. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class NullUnicodeBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new NullUnicodeBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public NullUnicodeBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return "\u0000"; 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with a \\u0000 body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a \\u0000 body"; 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/NullUnicodeSymbolBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends the null unicode symbol as body. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class NullUnicodeSymbolBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new NullUnicodeSymbolBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public NullUnicodeSymbolBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return "␀"; 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with a ␀ body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a ␀ body"; 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/RandomNegativeIntegerBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.generator.simple.NumberGenerator; 6 | import com.endava.cats.model.FuzzingData; 7 | import jakarta.inject.Inject; 8 | import jakarta.inject.Singleton; 9 | 10 | /** 11 | * Fuzzer used to send negative integers as body. 12 | */ 13 | @Singleton 14 | @HttpFuzzer 15 | public class RandomNegativeIntegerBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 16 | /** 17 | * Creates a new RandomNegativeIntegerBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public RandomNegativeIntegerBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | long value = Long.parseLong(NumberGenerator.generateVeryLargeInteger(3)); 29 | return String.valueOf(-value); 30 | } 31 | 32 | @Override 33 | protected String getScenario() { 34 | return "Send a request with an random negative integer body"; 35 | } 36 | 37 | @Override 38 | public String description() { 39 | return "send a request with a random negative integer body"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/RandomPositiveDecimalBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.generator.simple.NumberGenerator; 6 | import com.endava.cats.model.FuzzingData; 7 | import jakarta.inject.Inject; 8 | import jakarta.inject.Singleton; 9 | 10 | /** 11 | * Fuzzer that sends a positive decimal body. 12 | */ 13 | @Singleton 14 | @HttpFuzzer 15 | public class RandomPositiveDecimalBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 16 | /** 17 | * Creates a new RandomPositiveDecimalBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public RandomPositiveDecimalBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return NumberGenerator.generateVeryLargeDecimal(3); 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with an random positive decimal body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a random positive decimal body"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/RandomPositiveIntegerBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.generator.simple.NumberGenerator; 6 | import com.endava.cats.model.FuzzingData; 7 | import jakarta.inject.Inject; 8 | import jakarta.inject.Singleton; 9 | 10 | /** 11 | * Fuzzer that sends a random positive integer as body. 12 | */ 13 | @Singleton 14 | @HttpFuzzer 15 | public class RandomPositiveIntegerBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 16 | /** 17 | * Creates a new RandomPositiveIntegerBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public RandomPositiveIntegerBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return NumberGenerator.generateVeryLargeInteger(3); 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with a random positive integer body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a random positive integer body"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/RandomStringBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.generator.simple.StringGenerator; 6 | import com.endava.cats.model.FuzzingData; 7 | import jakarta.inject.Inject; 8 | import jakarta.inject.Singleton; 9 | 10 | /** 11 | * Fuzzer that sends a random string as a body. 12 | */ 13 | @Singleton 14 | @HttpFuzzer 15 | public class RandomStringBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 16 | /** 17 | * Creates a RandomStringBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public RandomStringBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return StringGenerator.generateRandomString(); 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with an random string body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a random string body"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/RandomUnicodeBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.generator.simple.UnicodeGenerator; 6 | import com.endava.cats.model.FuzzingData; 7 | import jakarta.inject.Inject; 8 | import jakarta.inject.Singleton; 9 | 10 | /** 11 | * Fuzzer that sends random unicode characters as body. 12 | */ 13 | @Singleton 14 | @HttpFuzzer 15 | public class RandomUnicodeBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 16 | /** 17 | * Creates a new RandomUnicodeBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public RandomUnicodeBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return String.join("", UnicodeGenerator.getControlCharsFields()); 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with an random unicode string body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with a random unicode string body"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/ZeroDecimalBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends decimal zero 0.0 as body. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class ZeroDecimalBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new ZeroDecimalBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public ZeroDecimalBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return "0.0"; 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with decimal 0.0 as body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with decimal 0.0 as body"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/http/ZeroIntegerBodyFuzzer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.http; 2 | 3 | import com.endava.cats.annotations.HttpFuzzer; 4 | import com.endava.cats.fuzzer.executor.SimpleExecutor; 5 | import com.endava.cats.model.FuzzingData; 6 | import jakarta.inject.Inject; 7 | import jakarta.inject.Singleton; 8 | 9 | /** 10 | * Fuzzer that sends the zero integer as a body. 11 | */ 12 | @Singleton 13 | @HttpFuzzer 14 | public class ZeroIntegerBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer { 15 | 16 | /** 17 | * Creates a new ZeroIntegerBodyFuzzer instance. 18 | * 19 | * @param executor the executor 20 | */ 21 | @Inject 22 | public ZeroIntegerBodyFuzzer(SimpleExecutor executor) { 23 | super(executor); 24 | } 25 | 26 | @Override 27 | protected String getPayload(FuzzingData data) { 28 | return "0"; 29 | } 30 | 31 | @Override 32 | protected String getScenario() { 33 | return "Send a request with integer 0 (zero) as body"; 34 | } 35 | 36 | @Override 37 | public String description() { 38 | return "send a request with integer 0 (zero) as body"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/api/BodyMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.api; 2 | 3 | import com.endava.cats.model.CatsHeader; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * Marker interface for mutators that mutate the request body. 9 | */ 10 | public interface BodyMutator extends Mutator { 11 | 12 | 13 | @Override 14 | default Collection mutate(Collection headers) { 15 | return headers; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/api/CustomMutatorConfig.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.api; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Stores the configuration of a custom mutator. Each filed corresponds to an entry in the custom mutator file. 7 | * 8 | * @param name the name of the custom mutator 9 | * @param type the fuzzing type, see {@code Type} 10 | * @param values the values that will be used for fuzzing 11 | */ 12 | public record CustomMutatorConfig(String name, Type type, List values) { 13 | 14 | public enum Type { 15 | TRAIL, INSERT, PREFIX, REPLACE, REPLACE_BODY, IN_BODY 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/api/CustomMutatorKeywords.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.api; 2 | 3 | /** 4 | * Keywords used by the custom mutator. 5 | */ 6 | public enum CustomMutatorKeywords { 7 | NAME, TYPE, VALUES 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/api/HeadersMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.api; 2 | 3 | /** 4 | * Marker interface for mutators that mutate the request headers. 5 | */ 6 | public interface HeadersMutator extends Mutator { 7 | 8 | @Override 9 | default String mutate(String inputJson, String selectedField) { 10 | return inputJson; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/LowercaseExpandingBytesMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import com.endava.cats.util.JsonUtils; 7 | import jakarta.inject.Singleton; 8 | 9 | @Singleton 10 | public class LowercaseExpandingBytesMutator implements BodyMutator { 11 | @Override 12 | public String mutate(String inputJson, String selectedField) { 13 | int length = String.valueOf(JsonUtils.getVariableFromJson(inputJson, selectedField)).length(); 14 | String generated = CatsUtil.selectRandom(UnicodeGenerator.getLowercaseExpandingBytes(), length); 15 | return CatsUtil.justReplaceField(inputJson, selectedField, generated).json(); 16 | } 17 | 18 | @Override 19 | public String description() { 20 | return "replace field with strings that expand bytes when lowercased"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/LowercaseExpandingLengthMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import com.endava.cats.util.JsonUtils; 7 | import jakarta.inject.Singleton; 8 | 9 | @Singleton 10 | public class LowercaseExpandingLengthMutator implements BodyMutator { 11 | @Override 12 | public String mutate(String inputJson, String selectedField) { 13 | int length = String.valueOf(JsonUtils.getVariableFromJson(inputJson, selectedField)).length(); 14 | String generated = CatsUtil.selectRandom(UnicodeGenerator.getLowercaseExpandingLength(), length); 15 | return CatsUtil.justReplaceField(inputJson, selectedField, generated).json(); 16 | } 17 | 18 | @Override 19 | public String description() { 20 | return "replace field with strings that expand length when lowercased"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/NullStringMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | 7 | /** 8 | * Sends null value in the target field. 9 | */ 10 | @Singleton 11 | public class NullStringMutator implements BodyMutator { 12 | 13 | @Override 14 | public String mutate(String inputJson, String selectedField) { 15 | return CatsUtil.justReplaceField(inputJson, selectedField, null).json(); 16 | } 17 | 18 | @Override 19 | public String description() { 20 | return "replace field with null"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomAlphanumericStringMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | import org.apache.commons.lang3.RandomStringUtils; 7 | 8 | /** 9 | * Sends a random alphanumeric value in the target field. 10 | */ 11 | @Singleton 12 | public class RandomAlphanumericStringMutator implements BodyMutator { 13 | private static final int BOUND = 100; 14 | 15 | @Override 16 | public String mutate(String inputJson, String selectedField) { 17 | int size = CatsUtil.random().nextInt(BOUND); 18 | return CatsUtil.justReplaceField(inputJson, selectedField, RandomStringUtils.secure().nextAlphanumeric(size)).json(); 19 | } 20 | 21 | @Override 22 | public String description() { 23 | return "replace field with random alphanumeric characters"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomControlCharsInFieldKeysMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.JsonUtils; 6 | import jakarta.inject.Singleton; 7 | 8 | /** 9 | * Inserts random values in the target field key. 10 | */ 11 | @Singleton 12 | public class RandomControlCharsInFieldKeysMutator implements BodyMutator { 13 | private static final int BOUND = 2; 14 | 15 | @Override 16 | public String mutate(String inputJson, String selectedField) { 17 | String randomControlChars = UnicodeGenerator.generateRandomUnicodeString(BOUND, Character::isISOControl); 18 | 19 | return JsonUtils.insertCharactersInFieldKey(inputJson, selectedField, randomControlChars); 20 | } 21 | 22 | @Override 23 | public String description() { 24 | return "insert random control chars in field keys"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomControlCharsMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import jakarta.inject.Singleton; 7 | 8 | /** 9 | * Sends random control chars in the target field. 10 | */ 11 | @Singleton 12 | public class RandomControlCharsMutator implements BodyMutator { 13 | private static final int BOUND = 10; 14 | 15 | @Override 16 | public String mutate(String inputJson, String selectedField) { 17 | String randomControlChars = UnicodeGenerator.generateRandomUnicodeString(BOUND, Character::isISOControl); 18 | 19 | return CatsUtil.justReplaceField(inputJson, selectedField, randomControlChars).json(); 20 | } 21 | 22 | @Override 23 | public String description() { 24 | return "replace field with random control chars"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomJsonMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import jakarta.inject.Singleton; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Sends a random json payloads replacing the entire input json. 12 | */ 13 | @Singleton 14 | public class RandomJsonMutator implements BodyMutator { 15 | 16 | @Override 17 | public String mutate(String inputJson, String selectedField) { 18 | List randomPayloads = UnicodeGenerator.getInvalidJsons(); 19 | 20 | return randomPayloads.get(CatsUtil.random().nextInt(randomPayloads.size())); 21 | } 22 | 23 | @Override 24 | public String description() { 25 | return "replace body with random invalid jsons"; 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomLargeIntegersMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | import org.apache.commons.lang3.RandomStringUtils; 7 | 8 | import java.math.BigInteger; 9 | 10 | /** 11 | * Sends a random large integers in the target field. 12 | */ 13 | @Singleton 14 | public class RandomLargeIntegersMutator implements BodyMutator { 15 | private static final int ITERATIONS = 5; 16 | private static final int LENGTH = 20; 17 | 18 | @Override 19 | public String mutate(String inputJson, String selectedField) { 20 | int i = 0; 21 | StringBuilder largeNumberBuilder = new StringBuilder(); 22 | while (i < ITERATIONS) { 23 | largeNumberBuilder.append(RandomStringUtils.secure().nextNumeric(LENGTH)); 24 | i++; 25 | } 26 | 27 | return CatsUtil.justReplaceField(inputJson, selectedField, new BigInteger(largeNumberBuilder.toString())).json(); 28 | } 29 | 30 | @Override 31 | public String description() { 32 | return "replace field with random large integers"; 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomMaxValuesMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Sends a random number max values in the target field. 11 | */ 12 | @Singleton 13 | public class RandomMaxValuesMutator implements BodyMutator { 14 | private static final List MAX_VALUES = List.of(Float.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, 15 | Double.MAX_VALUE, Byte.MAX_VALUE, Short.MAX_VALUE); 16 | 17 | @Override 18 | public String mutate(String inputJson, String selectedField) { 19 | Object toReplaceWith = MAX_VALUES.get(CatsUtil.random().nextInt(MAX_VALUES.size())); 20 | return CatsUtil.justReplaceField(inputJson, selectedField, toReplaceWith).json(); 21 | } 22 | 23 | @Override 24 | public String description() { 25 | return "replace field with random max values for int, long, float or double"; 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomMinValuesMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Sends a random number min values in the target field. 11 | */ 12 | @Singleton 13 | public class RandomMinValuesMutator implements BodyMutator { 14 | private static final List MIN_VALUES = List.of(Float.MIN_VALUE, Integer.MIN_VALUE, Long.MIN_VALUE, 15 | Double.MIN_VALUE, Byte.MIN_VALUE, Short.MIN_VALUE, Float.MIN_NORMAL, Double.MIN_NORMAL, -Float.MIN_VALUE, 16 | -Float.MIN_NORMAL, -Double.MIN_VALUE, -Double.MIN_NORMAL); 17 | 18 | @Override 19 | public String mutate(String inputJson, String selectedField) { 20 | Object toReplaceWith = MIN_VALUES.get(CatsUtil.random().nextInt(MIN_VALUES.size())); 21 | return CatsUtil.justReplaceField(inputJson, selectedField, toReplaceWith).json(); 22 | } 23 | 24 | @Override 25 | public String description() { 26 | return "replace field with random min values for int, long, float or double"; 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomNumberMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | import org.apache.commons.lang3.RandomStringUtils; 7 | 8 | 9 | /** 10 | * Sends a random number in the target field. 11 | */ 12 | @Singleton 13 | public class RandomNumberMutator implements BodyMutator { 14 | private static final int BOUND = 100; 15 | 16 | @Override 17 | public String mutate(String inputJson, String selectedField) { 18 | int size = CatsUtil.random().nextInt(BOUND); 19 | return CatsUtil.justReplaceField(inputJson, selectedField, RandomStringUtils.secure().nextNumeric(size)).json(); 20 | } 21 | 22 | @Override 23 | public String description() { 24 | return "replace field with random long numbers"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomPayloadSizeMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | 7 | /** 8 | * Mutates the JSON payload with a substring of random length from the input JSON. 9 | */ 10 | @Singleton 11 | public class RandomPayloadSizeMutator implements BodyMutator { 12 | 13 | @Override 14 | public String mutate(String inputJson, String selectedField) { 15 | int size = CatsUtil.random().nextInt(inputJson.length()); 16 | return CatsUtil.justReplaceField(inputJson, selectedField, inputJson.substring(0, size)).json(); 17 | } 18 | 19 | @Override 20 | public String description() { 21 | return "replace the payload with a substring of random length"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomStringMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.CatsUtil; 5 | import jakarta.inject.Singleton; 6 | import org.apache.commons.lang3.RandomStringUtils; 7 | 8 | /** 9 | * Sends a random unicode value in the target field. 10 | */ 11 | @Singleton 12 | public class RandomStringMutator implements BodyMutator { 13 | private static final int BOUND = 100; 14 | 15 | @Override 16 | public String mutate(String inputJson, String selectedField) { 17 | int size = CatsUtil.random().nextInt(BOUND); 18 | return CatsUtil.justReplaceField(inputJson, selectedField, RandomStringUtils.secure().next(size)).json(); 19 | } 20 | 21 | @Override 22 | public String description() { 23 | return "replace field with random unicode strings"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomTransferEncodingHeaderMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.HeadersMutator; 4 | import com.endava.cats.generator.Cloner; 5 | import com.endava.cats.model.CatsHeader; 6 | import com.google.common.net.HttpHeaders; 7 | import jakarta.inject.Singleton; 8 | import org.apache.commons.lang3.RandomStringUtils; 9 | 10 | import java.util.Collection; 11 | import java.util.Set; 12 | 13 | /** 14 | * Sends dummy values in the transfer encoding header 15 | */ 16 | @Singleton 17 | public class RandomTransferEncodingHeaderMutator implements HeadersMutator { 18 | @Override 19 | public Collection mutate(Collection headers) { 20 | Set clone = Cloner.cloneMe(headers); 21 | clone.add(CatsHeader.builder() 22 | .name(HttpHeaders.TRANSFER_ENCODING) 23 | .value(RandomStringUtils.secure().next(10)) 24 | .build()); 25 | return clone; 26 | } 27 | 28 | @Override 29 | public String description() { 30 | return "replace the transfer encoding header with random values"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomWhitespaceCharsMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import jakarta.inject.Singleton; 7 | 8 | /** 9 | * Sends random whitespaces in the target field. 10 | */ 11 | @Singleton 12 | public class RandomWhitespaceCharsMutator implements BodyMutator { 13 | private static final int BOUND = 15; 14 | 15 | @Override 16 | public String mutate(String inputJson, String selectedField) { 17 | String randomControlChars = UnicodeGenerator.generateRandomUnicodeString(BOUND, Character::isWhitespace); 18 | 19 | return CatsUtil.justReplaceField(inputJson, selectedField, randomControlChars).json(); 20 | } 21 | 22 | @Override 23 | public String description() { 24 | return "replace field with random whitespace chars"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RandomWhitespacesInFieldKeysMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.JsonUtils; 6 | import jakarta.inject.Singleton; 7 | 8 | /** 9 | * Inserts random values in the target field key. 10 | */ 11 | @Singleton 12 | public class RandomWhitespacesInFieldKeysMutator implements BodyMutator { 13 | private static final int BOUND = 2; 14 | 15 | @Override 16 | public String mutate(String inputJson, String selectedField) { 17 | String randomControlChars = UnicodeGenerator.generateRandomUnicodeString(BOUND, Character::isWhitespace); 18 | 19 | return JsonUtils.insertCharactersInFieldKey(inputJson, selectedField, randomControlChars); 20 | } 21 | 22 | @Override 23 | public String description() { 24 | return "insert random whitespaces in field keys"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/RemoveFieldMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.util.JsonUtils; 5 | import jakarta.inject.Singleton; 6 | 7 | /** 8 | * Removes the field from the json body. 9 | */ 10 | @Singleton 11 | public class RemoveFieldMutator implements BodyMutator { 12 | 13 | @Override 14 | public String mutate(String inputJson, String selectedField) { 15 | return JsonUtils.deleteNode(inputJson, selectedField); 16 | } 17 | 18 | @Override 19 | public String description() { 20 | return "remove field from the body"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/UppercaseExpandingBytesMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import com.endava.cats.util.JsonUtils; 7 | import jakarta.inject.Singleton; 8 | 9 | @Singleton 10 | public class UppercaseExpandingBytesMutator implements BodyMutator { 11 | @Override 12 | public String mutate(String inputJson, String selectedField) { 13 | int length = String.valueOf(JsonUtils.getVariableFromJson(inputJson, selectedField)).length(); 14 | String generated = CatsUtil.selectRandom(UnicodeGenerator.getUppercaseExpandingBytes(), length); 15 | return CatsUtil.justReplaceField(inputJson, selectedField, generated).json(); 16 | } 17 | 18 | @Override 19 | public String description() { 20 | return "replace field with strings that expand bytes when uppercased"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/fuzzer/special/mutators/impl/UppercaseExpandingLengthMutator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.special.mutators.impl; 2 | 3 | import com.endava.cats.fuzzer.special.mutators.api.BodyMutator; 4 | import com.endava.cats.generator.simple.UnicodeGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import com.endava.cats.util.JsonUtils; 7 | import jakarta.inject.Singleton; 8 | 9 | @Singleton 10 | public class UppercaseExpandingLengthMutator implements BodyMutator { 11 | @Override 12 | public String mutate(String inputJson, String selectedField) { 13 | int length = String.valueOf(JsonUtils.getVariableFromJson(inputJson, selectedField)).length(); 14 | String generated = CatsUtil.selectRandom(UnicodeGenerator.getUppercaseExpandingLength(), length); 15 | return CatsUtil.justReplaceField(inputJson, selectedField, generated).json(); 16 | } 17 | 18 | @Override 19 | public String description() { 20 | return "replace field with strings that expand length when uppercased"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/Cloner.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator; 2 | 3 | import com.endava.cats.model.CatsHeader; 4 | 5 | import java.util.Collection; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * Used to clone specific objects 11 | */ 12 | public class Cloner { 13 | 14 | private Cloner() { 15 | //ntd 16 | } 17 | 18 | /** 19 | * Creates a new set containing cloned copies of the provided collection of CatsHeader objects. 20 | * 21 | * @param items The collection of CatsHeader objects to clone. 22 | * @return A new set containing cloned copies of the provided CatsHeader objects. 23 | */ 24 | public static Set cloneMe(Collection items) { 25 | Set clones = new HashSet<>(); 26 | 27 | for (CatsHeader t : items) { 28 | clones.add(t.copy()); 29 | } 30 | 31 | return clones; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/api/DataFormatGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | /** 4 | * This interface defines an abstract class for data format generators. 5 | * A data format generator is responsible for generating data in a specific format. 6 | */ 7 | public interface DataFormatGenerator { 8 | /** 9 | * Returns a Predicate to check if the Generator applies to the given format or propertyName 10 | * 11 | * @param format the OpenAPI format 12 | * @param propertyName the name of tje property 13 | * @return true if the Generator can be applied to the given input 14 | */ 15 | boolean appliesTo(String format, String propertyName); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/api/InvalidDataFormat.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | import io.swagger.v3.oas.models.media.Schema; 4 | import jakarta.enterprise.inject.Instance; 5 | import jakarta.inject.Inject; 6 | import jakarta.inject.Singleton; 7 | 8 | /** 9 | * Keeps a mapping between OpenAPI format types and CATs generators 10 | */ 11 | @Singleton 12 | public class InvalidDataFormat extends DataFormat { 13 | /** 14 | * Creates a new InvalidDataFormat. 15 | * 16 | * @param generators a list of registered invalid data generators 17 | */ 18 | @Inject 19 | public InvalidDataFormat(Instance generators) { 20 | super(generators); 21 | } 22 | 23 | /** 24 | * Returns the proper generator for the provided schema and/or property name. 25 | * 26 | * @param schema the field schema 27 | * @param propertyName the name of the property 28 | * @return a generator for the given schema and property name 29 | */ 30 | public InvalidDataFormatGenerator generator(Schema schema, String propertyName) { 31 | return super.getGenerators(schema, propertyName) 32 | .stream() 33 | .findFirst() 34 | .orElse(new VoidGenerator()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/api/InvalidDataFormatGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | /** 4 | * Provide implementation for different formats 5 | */ 6 | public interface InvalidDataFormatGenerator extends DataFormatGenerator { 7 | 8 | /** 9 | * This method will provide values which seem almost valid for the given format. For example: for an email field something like 'cats@cats.' 10 | * 11 | * @return an almost valid string based on the associated format 12 | */ 13 | String getAlmostValidValue(); 14 | 15 | /** 16 | * This method will provide values which are obviously not valid for the given format. For example: for an email field something like 'cats'. 17 | * 18 | * @return a wrong value based on the associated format 19 | */ 20 | String getTotallyWrongValue(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/api/OpenAPIFormat.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Marks forms supported by a specific format generator. 7 | */ 8 | public interface OpenAPIFormat { 9 | 10 | /** 11 | * Provides a list of OpenAPI formats supported by a {@code DataFormatGenerator} 12 | * 13 | * @return a list of OpenAPI formats 14 | */ 15 | List matchingFormats(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/api/PropertySanitizer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | import java.util.Locale; 4 | 5 | /** 6 | * An interface defining a property sanitizer. 7 | *

8 | * A property sanitizer is responsible for sanitizing a property value by removing any unwanted characters. 9 | */ 10 | public interface PropertySanitizer { 11 | 12 | /** 13 | * Sanitizes the given string by removing any hyphens (-), underscores (_), and hash symbols (#). 14 | * The sanitized string is also converted to lowercase using the default locale. 15 | * 16 | * @param string The string to sanitize 17 | * @return The sanitized string 18 | */ 19 | static String sanitize(String string) { 20 | return string.replaceAll("[-_#]+", "").toLowerCase(Locale.ROOT); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/api/ValidDataFormatGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | import io.swagger.v3.oas.models.media.Schema; 4 | 5 | /** 6 | * Generates valid data based on the OpenAPI format. 7 | */ 8 | public interface ValidDataFormatGenerator extends DataFormatGenerator { 9 | 10 | /** 11 | * Generates a value based on the given format 12 | * 13 | * @param schema the type of the property 14 | * @return a valid value matching the format 15 | */ 16 | Object generate(Schema schema); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/api/VoidGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | import io.swagger.v3.oas.models.media.Schema; 4 | 5 | /** 6 | * Void data generator. 7 | */ 8 | public class VoidGenerator implements ValidDataFormatGenerator, InvalidDataFormatGenerator { 9 | @Override 10 | public Object generate(Schema format) { 11 | return null; 12 | } 13 | 14 | @Override 15 | public boolean appliesTo(String format, String propertyName) { 16 | return true; 17 | } 18 | 19 | @Override 20 | public String getAlmostValidValue() { 21 | return null; 22 | } 23 | 24 | @Override 25 | public String getTotallyWrongValue() { 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/AddressLine2Generator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates real line2 addresses. 15 | */ 16 | @Singleton 17 | public class AddressLine2Generator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "line2".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("line2"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("line2"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String finalAddress = "Floor " + CatsUtil.random().nextInt(20) + ", Suite " + CatsUtil.random().nextInt(10); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, finalAddress); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/CardholderNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates real world person names. 15 | */ 16 | @Singleton 17 | public class CardholderNameGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "personname".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("cardholdername"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("cardHolderName", "card_holder_name", "card-holder-name", ""); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().name().name(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/ContentTypeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.PropertySanitizer; 5 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 6 | import com.endava.cats.generator.simple.StringGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates content types. 15 | */ 16 | @Singleton 17 | public class ContentTypeGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "contenttype".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("contenttype"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("contentType", "content-type"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | int generated = CatsUtil.random().nextInt(StringGenerator.getUnsupportedMediaTypes().size()); 33 | 34 | return StringGenerator.getUnsupportedMediaTypes().get(generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/DescriptionGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates quotes to fill in description fields. 15 | */ 16 | @Singleton 17 | public class DescriptionGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "description".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("description"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("description"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().chuckNorris().fact(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/FirstNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates readable first names. 15 | */ 16 | @Singleton 17 | public class FirstNameGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "firstname".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("firstname"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("firstName", "firstname", "first-name", "first_name"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().name().firstName(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/FullNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generator for full names. 15 | */ 16 | @Singleton 17 | public class FullNameGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "fullname".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("fullname"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("fullName", "full-name", "full_name"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().name().fullName(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/GenderGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.PropertySanitizer; 5 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 6 | import com.endava.cats.util.CatsUtil; 7 | import io.swagger.v3.oas.models.media.Schema; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * A generator class implementing interfaces for generating valid gender data formats. 14 | */ 15 | @Singleton 16 | public class GenderGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 17 | private static final List GENDER = List.of("Male", "Female", "Other"); 18 | private static final String GENDER_WORD = "gender"; 19 | 20 | @Override 21 | public Object generate(Schema schema) { 22 | return CatsUtil.selectRandom(GENDER); 23 | } 24 | 25 | @Override 26 | public boolean appliesTo(String format, String propertyName) { 27 | return GENDER_WORD.equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 28 | PropertySanitizer.sanitize(propertyName).equalsIgnoreCase(GENDER_WORD); 29 | } 30 | 31 | @Override 32 | public List matchingFormats() { 33 | return List.of(GENDER_WORD); 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/Gtin8Generator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.PropertySanitizer; 5 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 6 | import com.endava.cats.generator.simple.StringGenerator; 7 | import io.swagger.v3.oas.models.media.Schema; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * A generator class implementing interfaces for generating valid GTIN-8 (Global Trade Item Number) data formats. 14 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 15 | */ 16 | @Singleton 17 | public class Gtin8Generator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | @Override 19 | public Object generate(Schema schema) { 20 | return StringGenerator.generate("[0-9]+", 8, 8); 21 | } 22 | 23 | @Override 24 | public boolean appliesTo(String format, String propertyName) { 25 | return "ean8".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 26 | "gtin8".equalsIgnoreCase(PropertySanitizer.sanitize(format)); 27 | } 28 | 29 | @Override 30 | public List matchingFormats() { 31 | return List.of("gtin8", "ean8"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/IRIGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import io.swagger.v3.oas.models.media.Schema; 7 | import jakarta.inject.Singleton; 8 | 9 | import java.util.List; 10 | import java.util.Locale; 11 | 12 | /** 13 | * A generator class implementing interfaces for generating valid International Reference Numbers (IRN) data formats. 14 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 15 | */ 16 | @Singleton 17 | public class IRIGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | @Override 19 | public Object generate(Schema schema) { 20 | String generated = CatsUtil.faker().ancient().god().toLowerCase(Locale.ROOT); 21 | 22 | return "https://ë-%s.com/cats".formatted(generated); 23 | } 24 | 25 | @Override 26 | public boolean appliesTo(String format, String propertyName) { 27 | return "iri".equalsIgnoreCase(format); 28 | } 29 | 30 | @Override 31 | public List matchingFormats() { 32 | return List.of("iri"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/IRIReferenceGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | import org.apache.commons.lang3.RandomStringUtils; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * A generator class implementing interfaces for generating valid Internationalized Resource Identifiers (IRI) data formats. 13 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 14 | */ 15 | @Singleton 16 | public class IRIReferenceGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 17 | @Override 18 | public Object generate(Schema schema) { 19 | String generated = RandomStringUtils.secure().nextAlphabetic(5); 20 | return "/füzzing%s/".formatted(generated); 21 | } 22 | 23 | @Override 24 | public boolean appliesTo(String format, String propertyName) { 25 | return "iri-reference".equalsIgnoreCase(format); 26 | } 27 | 28 | @Override 29 | public List matchingFormats() { 30 | return List.of("iri-reference"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/IbanGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates real IBANs 15 | */ 16 | @Singleton 17 | public class IbanGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "iban".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("iban"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("iban"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().finance().iban(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/IdnEmailGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import io.swagger.v3.oas.models.media.Schema; 7 | import jakarta.inject.Singleton; 8 | 9 | import java.util.List; 10 | import java.util.Locale; 11 | 12 | /** 13 | * A generator class implementing interfaces for generating valid IDN (Internationalized Domain Name) email data formats. 14 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 15 | */ 16 | @Singleton 17 | public class IdnEmailGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | @Override 19 | public Object generate(Schema schema) { 20 | return CatsUtil.faker().ancient().primordial().toLowerCase(Locale.ROOT) + ".cööl.cats@cats.io"; 21 | } 22 | 23 | @Override 24 | public boolean appliesTo(String format, String propertyName) { 25 | return "idn-email".equalsIgnoreCase(format); 26 | } 27 | 28 | @Override 29 | public List matchingFormats() { 30 | return List.of("idn-email"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/IdnHostnameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import io.swagger.v3.oas.models.media.Schema; 7 | import jakarta.inject.Singleton; 8 | 9 | import java.util.List; 10 | import java.util.Locale; 11 | 12 | /** 13 | * A generator class implementing interfaces for generating valid IDN (Internationalized Domain Name) hostname data formats. 14 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 15 | */ 16 | @Singleton 17 | public class IdnHostnameGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | @Override 19 | public Object generate(Schema schema) { 20 | String generated = CatsUtil.faker().ancient().titan().toLowerCase(Locale.ROOT); 21 | 22 | return "www.ë%s.com".formatted(generated); 23 | } 24 | 25 | @Override 26 | public boolean appliesTo(String format, String propertyName) { 27 | return "idn-hostname".equalsIgnoreCase(format); 28 | } 29 | 30 | @Override 31 | public List matchingFormats() { 32 | return List.of("idn-hostname"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/JsonPointerGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * A generator class implementing interfaces for generating valid JSON Pointer data formats. 12 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 13 | */ 14 | @Singleton 15 | public class JsonPointerGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 16 | @Override 17 | public Object generate(Schema schema) { 18 | return "/item/0/id"; 19 | } 20 | 21 | @Override 22 | public boolean appliesTo(String format, String propertyName) { 23 | return "json-pointer".equalsIgnoreCase(format); 24 | } 25 | 26 | @Override 27 | public List matchingFormats() { 28 | return List.of("json-pointer"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/KvPairsGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * A generator class implementing interfaces for generating valid key-value pairs data formats. 13 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 14 | */ 15 | @Singleton 16 | public class KvPairsGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 17 | 18 | @Override 19 | public boolean appliesTo(String format, String propertyName) { 20 | return "kvpairs".equalsIgnoreCase(format); 21 | } 22 | 23 | @Override 24 | public Object generate(Schema schema) { 25 | return Map.of("key", "value", "anotherKey", "anotherValue"); 26 | } 27 | 28 | @Override 29 | public List matchingFormats() { 30 | return List.of("kvpairs"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/LastNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates valid last names. 15 | */ 16 | @Singleton 17 | public class LastNameGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "lastname".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("lastname"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("lastName", "lastname", "last-name", "last_name"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().name().lastName(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/MiddleNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generator for middle names. 15 | */ 16 | @Singleton 17 | public class MiddleNameGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "middlename".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("middlename"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("middleNAme", "middlename", "middle-name", "middle_name"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().name().firstName(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/NationalityGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.PropertySanitizer; 5 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 6 | import io.swagger.v3.oas.models.media.Schema; 7 | import jakarta.inject.Singleton; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Generates real world nationalities. 13 | */ 14 | @Singleton 15 | public class NationalityGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 16 | private final CountryCodeGenerator countryCodeGenerator; 17 | 18 | public NationalityGenerator(CountryCodeGenerator countryCodeGenerator) { 19 | this.countryCodeGenerator = countryCodeGenerator; 20 | } 21 | 22 | @Override 23 | public boolean appliesTo(String format, String propertyName) { 24 | return "nationality".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 25 | PropertySanitizer.sanitize(propertyName).endsWith("nationality"); 26 | } 27 | 28 | @Override 29 | public List matchingFormats() { 30 | return List.of("nationality"); 31 | } 32 | 33 | @Override 34 | public Object generate(Schema schema) { 35 | return countryCodeGenerator.generate(schema); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/PeriodGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import com.endava.cats.util.CatsUtil; 6 | import io.swagger.v3.oas.models.media.Schema; 7 | import jakarta.inject.Singleton; 8 | 9 | import java.time.Period; 10 | import java.util.List; 11 | 12 | /** 13 | * A generator class implementing interfaces for generating valid Period data formats. 14 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 15 | */ 16 | @Singleton 17 | public class PeriodGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | @Override 19 | public Object generate(Schema schema) { 20 | return Period.of(CatsUtil.random().nextInt(30), CatsUtil.random().nextInt(26), CatsUtil.random().nextInt(22)); 21 | } 22 | 23 | @Override 24 | public boolean appliesTo(String format, String propertyName) { 25 | return "period".equalsIgnoreCase(format); 26 | } 27 | 28 | @Override 29 | public List matchingFormats() { 30 | return List.of("period"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/RegexGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * A generator class implementing interfaces for generating valid data formats based on regular expressions. 12 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 13 | */ 14 | @Singleton 15 | public class RegexGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 16 | @Override 17 | public Object generate(Schema schema) { 18 | return "[a-z0-9]+"; 19 | } 20 | 21 | @Override 22 | public boolean appliesTo(String format, String propertyName) { 23 | return "regex".equalsIgnoreCase(format); 24 | } 25 | 26 | @Override 27 | public List matchingFormats() { 28 | return List.of("regex"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/RelativeJsonPointerGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * A generator class implementing interfaces for generating valid relative JSON Pointer data formats. 12 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 13 | */ 14 | @Singleton 15 | public class RelativeJsonPointerGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 16 | @Override 17 | public Object generate(Schema schema) { 18 | return "1/id"; 19 | } 20 | 21 | @Override 22 | public boolean appliesTo(String format, String propertyName) { 23 | return "relative-json-pointer".equalsIgnoreCase(format); 24 | } 25 | 26 | @Override 27 | public List matchingFormats() { 28 | return List.of("relative-json-pointer"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/SortCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates real world sort codes. 15 | */ 16 | @Singleton 17 | public class SortCodeGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "sortcode".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("sortcode"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("sort-code", "sortCode"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().numerify("## ## ##"); 33 | 34 | return DataFormat.matchesPatternOrNullWithCombinations(schema, generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/StateCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates valid state codes. 15 | */ 16 | @Singleton 17 | public class StateCodeGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "statecode".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("statecode"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("state-code", "stateCode"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().address().stateAbbr(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/TimeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | 8 | import java.time.OffsetTime; 9 | import java.time.ZoneId; 10 | import java.time.format.DateTimeFormatter; 11 | import java.util.List; 12 | 13 | /** 14 | * A generator class implementing interfaces for generating valid time data formats. 15 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 16 | */ 17 | @Singleton 18 | public class TimeGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 19 | @Override 20 | public Object generate(Schema schema) { 21 | return OffsetTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ISO_OFFSET_TIME); 22 | } 23 | 24 | @Override 25 | public boolean appliesTo(String format, String propertyName) { 26 | return "time".equalsIgnoreCase(format); 27 | } 28 | 29 | @Override 30 | public List matchingFormats() { 31 | return List.of("time"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/TimeOfDayGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.PropertySanitizer; 5 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 6 | import com.endava.cats.util.CatsUtil; 7 | import io.swagger.v3.oas.models.media.Schema; 8 | import jakarta.inject.Singleton; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Generates random time of day in HH:mm format. 14 | */ 15 | @Singleton 16 | public class TimeOfDayGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 17 | @Override 18 | public Object generate(Schema schema) { 19 | int hour = CatsUtil.random().nextInt(24); 20 | int minute = CatsUtil.random().nextInt(60); 21 | 22 | return String.format("%02d:%02d", hour, minute); 23 | } 24 | 25 | @Override 26 | public boolean appliesTo(String format, String propertyName) { 27 | return PropertySanitizer.sanitize(propertyName).endsWith("time") && 28 | !"time".equalsIgnoreCase(format); 29 | } 30 | 31 | @Override 32 | public List matchingFormats() { 33 | return List.of("time"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/URIReferenceGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | import org.apache.commons.lang3.RandomStringUtils; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * A generator class implementing interfaces for generating valid URI (Uniform Resource Identifier) reference data formats. 13 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 14 | */ 15 | @Singleton 16 | public class URIReferenceGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 17 | @Override 18 | public Object generate(Schema schema) { 19 | return "/fuzzing%s/".formatted(RandomStringUtils.secure().nextAlphabetic(4)); 20 | } 21 | 22 | @Override 23 | public boolean appliesTo(String format, String propertyName) { 24 | return "uri-reference".equalsIgnoreCase(format); 25 | } 26 | 27 | @Override 28 | public List matchingFormats() { 29 | return List.of("uri-reference"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/URITemplateGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 5 | import io.swagger.v3.oas.models.media.Schema; 6 | import jakarta.inject.Singleton; 7 | import org.apache.commons.lang3.RandomStringUtils; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * A generator class implementing interfaces for generating valid URI (Uniform Resource Identifier) template data formats. 13 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 14 | */ 15 | @Singleton 16 | public class URITemplateGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 17 | @Override 18 | public Object generate(Schema schema) { 19 | return "/fuzzing%s/{path}".formatted(RandomStringUtils.secure().nextAlphabetic(4)); 20 | } 21 | 22 | @Override 23 | public boolean appliesTo(String format, String propertyName) { 24 | return "uri-template".equalsIgnoreCase(format); 25 | } 26 | 27 | @Override 28 | public List matchingFormats() { 29 | return List.of("uri-template"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/UnixtimeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.OpenAPIFormat; 4 | import com.endava.cats.generator.format.api.PropertySanitizer; 5 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 6 | import io.swagger.v3.oas.models.media.Schema; 7 | import jakarta.inject.Singleton; 8 | 9 | import java.time.Instant; 10 | import java.util.List; 11 | 12 | /** 13 | * A generator class implementing interfaces for generating valid Unix time data formats. 14 | * It implements the ValidDataFormatGenerator and OpenAPIFormat interfaces. 15 | */ 16 | @Singleton 17 | public class UnixtimeGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | @Override 19 | public boolean appliesTo(String format, String propertyName) { 20 | return "unixtime".equalsIgnoreCase(PropertySanitizer.sanitize(format)); 21 | } 22 | 23 | @Override 24 | public Object generate(Schema schema) { 25 | return Instant.now().minusSeconds(1).getEpochSecond(); 26 | } 27 | 28 | @Override 29 | public List matchingFormats() { 30 | return List.of("unix-time", "unixtime", "unix_time"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/generator/format/impl/UsernameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import com.endava.cats.generator.format.api.DataFormat; 4 | import com.endava.cats.generator.format.api.OpenAPIFormat; 5 | import com.endava.cats.generator.format.api.PropertySanitizer; 6 | import com.endava.cats.generator.format.api.ValidDataFormatGenerator; 7 | import com.endava.cats.util.CatsUtil; 8 | import io.swagger.v3.oas.models.media.Schema; 9 | import jakarta.inject.Singleton; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Generates readable usernames. 15 | */ 16 | @Singleton 17 | public class UsernameGenerator implements ValidDataFormatGenerator, OpenAPIFormat { 18 | 19 | @Override 20 | public boolean appliesTo(String format, String propertyName) { 21 | return "username".equalsIgnoreCase(PropertySanitizer.sanitize(format)) || 22 | PropertySanitizer.sanitize(propertyName).endsWith("username"); 23 | } 24 | 25 | @Override 26 | public List matchingFormats() { 27 | return List.of("username", "userName"); 28 | } 29 | 30 | @Override 31 | public Object generate(Schema schema) { 32 | String generated = CatsUtil.faker().name().username(); 33 | 34 | return DataFormat.matchesPatternOrNull(schema, generated); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/http/ResponseCodeFamilyDynamic.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.http; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Objects; 6 | import java.util.Optional; 7 | 8 | /** 9 | * Class used to create dynamic http response code sets. 10 | */ 11 | public class ResponseCodeFamilyDynamic implements ResponseCodeFamily { 12 | private final List responseCodes; 13 | 14 | public ResponseCodeFamilyDynamic(List responseCodes) { 15 | this.responseCodes = List.copyOf(responseCodes); 16 | } 17 | 18 | @Override 19 | public String asString() { 20 | return String.join("|", Optional.ofNullable(responseCodes).orElse(Collections.emptyList())); 21 | } 22 | 23 | @Override 24 | public List allowedResponseCodes() { 25 | return Optional.ofNullable(responseCodes).orElse(Collections.emptyList()); 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (o instanceof ResponseCodeFamilyDynamic that) { 31 | return Objects.equals(responseCodes, that.responseCodes); 32 | } 33 | return false; 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | return Objects.hashCode(responseCodes); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/CatsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import com.endava.cats.http.HttpMethod; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * This class is used to store the configuration context for the Cats application. 9 | */ 10 | public record CatsConfiguration(String version, String contract, String basePath, 11 | List httpMethods, int fuzzers, int pathsToRun, int totalPaths) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/CatsField.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import io.swagger.v3.oas.models.media.Schema; 4 | import lombok.Builder; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.Getter; 7 | import lombok.ToString; 8 | 9 | /** 10 | * An internal representation of a field from OpenAPI. 11 | */ 12 | @Builder 13 | @ToString(of = {"name", "required"}) 14 | @EqualsAndHashCode(of = "name") 15 | @Getter 16 | public class CatsField { 17 | private final String name; 18 | private final boolean required; 19 | private final boolean readOnly; 20 | private final boolean writeOnly; 21 | private final Schema schema; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/CatsRequest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import com.endava.cats.util.KeyValuePair; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | import java.time.OffsetDateTime; 9 | import java.time.format.DateTimeFormatter; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | /** 14 | * Model class used to stored request details. 15 | */ 16 | @Getter 17 | @Setter 18 | @Builder 19 | public class CatsRequest { 20 | List> headers; 21 | String payload; 22 | String httpMethod; 23 | String url; 24 | 25 | @Builder.Default 26 | String timestamp = DateTimeFormatter.RFC_1123_DATE_TIME.format(OffsetDateTime.now()); 27 | 28 | /** 29 | * Creates an empty CatsRequest with placeholder values. 30 | * The generated request has an empty JSON payload, an undefined HTTP method ("####"), 31 | * an undefined URL ("####"), and an empty list of headers. 32 | * 33 | * @return An empty CatsRequest instance. 34 | */ 35 | public static CatsRequest empty() { 36 | CatsRequest request = CatsRequest.builder().build(); 37 | request.payload = "{}"; 38 | request.httpMethod = "####"; 39 | request.url = "####"; 40 | request.headers = Collections.emptyList(); 41 | return request; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/CatsTestCaseExecutionSummary.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | /** 4 | * Used to hold only details about execution. 5 | * 6 | * @param path the service path 7 | * @param httpMethod the http method 8 | * @param responseTimeInMs the response time in ms 9 | */ 10 | public record CatsTestCaseExecutionSummary(String testId, String path, String httpMethod, long responseTimeInMs) { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/CustomFuzzerExecution.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.util.Comparator; 7 | import java.util.Objects; 8 | 9 | /** 10 | * Represents the execution details of a custom fuzzer. It includes information about the fuzzing data, 11 | * the associated test ID, and the test entry object. 12 | */ 13 | @Builder 14 | @Getter 15 | public class CustomFuzzerExecution implements Comparable { 16 | private final FuzzingData fuzzingData; 17 | private final String testId; 18 | private final Object testEntry; 19 | 20 | @Override 21 | public int compareTo(CustomFuzzerExecution o) { 22 | return Comparator.comparing((CustomFuzzerExecution c) -> c.getFuzzingData().getPath()) 23 | .thenComparing(CustomFuzzerExecution::getTestId) 24 | .compare(this, o); 25 | } 26 | 27 | @Override 28 | public boolean equals(Object o) { 29 | if (!(o instanceof CustomFuzzerExecution that)) { 30 | return false; 31 | } 32 | return Objects.equals(fuzzingData.getPath(), that.fuzzingData.getPath()) && Objects.equals(testId, that.testId); 33 | } 34 | 35 | @Override 36 | public int hashCode() { 37 | return Objects.hash(fuzzingData.getPath(), testId); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/FuzzingConstraints.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.util.Locale; 7 | 8 | /** 9 | * Represents constraints related to fuzzing, including information about the presence of a minimum length 10 | * and whether required fields have been fuzzed. 11 | */ 12 | @Builder 13 | @Getter 14 | public class FuzzingConstraints { 15 | private final boolean hasMinlength; 16 | private final boolean hasRequiredFieldsFuzzed; 17 | 18 | /** 19 | * Checks if either a minimum length or mandatory fields have been fuzzed. 20 | * 21 | * @return {@code true} if there is a minimum length or mandatory fields have been fuzzed, {@code false} otherwise. 22 | */ 23 | public boolean hasMinLengthOrMandatoryFieldsFuzzed() { 24 | return hasMinlength || hasRequiredFieldsFuzzed; 25 | } 26 | 27 | /** 28 | * Gets a string representation of the required constraints. 29 | * 30 | * @return A string indicating whether required fields have been fuzzed and, if not, whether there is a minimum length. 31 | */ 32 | public String getRequiredString() { 33 | return String.valueOf(hasRequiredFieldsFuzzed).toUpperCase(Locale.ROOT) + (hasMinlength && !hasRequiredFieldsFuzzed ? " but has minLength" : ""); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/NoMediaType.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import io.swagger.v3.oas.models.media.MediaType; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | 6 | /** 7 | * Represents a custom media type indicating an empty body. 8 | * Extends {@link io.swagger.v3.oas.models.media.MediaType MediaType}. 9 | */ 10 | public class NoMediaType extends MediaType { 11 | /** 12 | * Constant representing an empty body. 13 | */ 14 | public static final String EMPTY_BODY = "empty_body"; 15 | 16 | /** 17 | * Schema for an empty body. 18 | */ 19 | public static final Schema EMPTY_BODY_SCHEMA; 20 | 21 | static { 22 | EMPTY_BODY_SCHEMA = new Schema<>(); 23 | EMPTY_BODY_SCHEMA.set$ref(EMPTY_BODY); 24 | EMPTY_BODY_SCHEMA.setExample("{}"); 25 | } 26 | 27 | @Override 28 | public Schema getSchema() { 29 | return EMPTY_BODY_SCHEMA; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/ProcessingError.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | /** 4 | * Represents an error that occurred during the fuzzer processing. 5 | */ 6 | public record ProcessingError(String path, String httpMethod, String message) { 7 | 8 | @Override 9 | public String toString() { 10 | String firstPart = path != null ? "Path %s, ".formatted(path) : ""; 11 | String secondPart = httpMethod != null ? "http method %s: ".formatted(httpMethod) : ""; 12 | 13 | return "%s%s%s".formatted(firstPart, secondPart, message); 14 | } 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/TimeExecution.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | /** 7 | * Holds a mapping between test identifiers and execution times in ms. 8 | */ 9 | @Builder 10 | @Getter 11 | public class TimeExecution { 12 | private long executionInMs; 13 | private String testId; 14 | 15 | /** 16 | * Generates a string representation of the execution time, including the test identifier and duration in milliseconds. 17 | * 18 | * @return A formatted string representing the test identifier and execution time in milliseconds. 19 | */ 20 | public String executionTimeString() { 21 | return testId + " - " + executionInMs + "ms"; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return executionTimeString(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/TimeExecutionDetails.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | import lombok.ToString; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Entity holding details about time execution details for test cases. 11 | */ 12 | @Builder 13 | @Getter 14 | @ToString 15 | public class TimeExecutionDetails { 16 | private final String path; 17 | private final List executions; 18 | private final TimeExecution bestCase; 19 | private final TimeExecution worstCase; 20 | private final double average; 21 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/ann/Exclude.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model.ann; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Use this to mark fields or classes which are excluded from json serialization when creating the reports 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ElementType.FIELD, ElementType.TYPE}) 13 | public @interface Exclude { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/model/ann/ExcludeTestCaseStrategy.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model.ann; 2 | 3 | import com.google.gson.ExclusionStrategy; 4 | import com.google.gson.FieldAttributes; 5 | 6 | /** 7 | * Gson exclusion strategy that excludes fields and classes annotated with {@code Exclude}. 8 | */ 9 | public class ExcludeTestCaseStrategy implements ExclusionStrategy { 10 | 11 | @Override 12 | public boolean shouldSkipClass(Class clazz) { 13 | return clazz.getAnnotation(Exclude.class) != null; 14 | } 15 | 16 | @Override 17 | public boolean shouldSkipField(FieldAttributes f) { 18 | return f.getAnnotation(Exclude.class) != null; 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/strategy/InsertFuzzingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | import com.endava.cats.util.CatsUtil; 4 | 5 | /** 6 | * Fuzzing strategy that inserts fuzzed values into valid data. 7 | */ 8 | public final class InsertFuzzingStrategy extends FuzzingStrategy { 9 | @Override 10 | public Object process(Object value) { 11 | return CatsUtil.insertInTheMiddle(String.valueOf(value), String.valueOf(data), true); 12 | } 13 | 14 | @Override 15 | public String name() { 16 | return "INSERT"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/strategy/NoopFuzzingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | /** 4 | * Fuzzing strategy that doesn't do anything. 5 | */ 6 | public final class NoopFuzzingStrategy extends FuzzingStrategy { 7 | @Override 8 | public Object process(Object value) { 9 | return value; 10 | } 11 | 12 | @Override 13 | public String name() { 14 | return "NOOP"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/strategy/PrefixFuzzingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | /** 4 | * Fuzzing strategy that prefixes valid data with fuzzed values. 5 | */ 6 | public final class PrefixFuzzingStrategy extends FuzzingStrategy { 7 | @Override 8 | public Object process(Object value) { 9 | return data + String.valueOf(value); 10 | } 11 | 12 | @Override 13 | public String name() { 14 | return "PREFIX"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/strategy/ReplaceFuzzingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | /** 4 | * Fuzzing strategy that replaces valid data with fuzzed values. 5 | */ 6 | public final class ReplaceFuzzingStrategy extends FuzzingStrategy { 7 | 8 | @Override 9 | public Object process(Object value) { 10 | return data; 11 | } 12 | 13 | @Override 14 | public String name() { 15 | return "REPLACE"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/strategy/SkipFuzzingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | /** 4 | * Fuzzing strategy marking the actual fuzzing was not performed, but rather skipped. 5 | */ 6 | public final class SkipFuzzingStrategy extends FuzzingStrategy { 7 | @Override 8 | public Object process(Object value) { 9 | return data; 10 | } 11 | 12 | @Override 13 | public String name() { 14 | return "SKIP"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/strategy/TrailFuzzingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | /** 4 | * Fuzzing strategy that trails valid data with fuzzed values. 5 | */ 6 | public final class TrailFuzzingStrategy extends FuzzingStrategy { 7 | @Override 8 | public Object process(Object value) { 9 | return value + String.valueOf(data); 10 | } 11 | 12 | @Override 13 | public String name() { 14 | return "TRAIL"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/util/FuzzingResult.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | /** 4 | * A record representing the result of a fuzzing operation, containing both the fuzzed JSON and the corresponding fuzzed value. 5 | * 6 | * @param json The fuzzed JSON representation. 7 | * @param fuzzedValue The corresponding fuzzed value. 8 | */ 9 | public record FuzzingResult(String json, Object fuzzedValue) { 10 | 11 | /** 12 | * Creates an empty {@code FuzzingResult} with empty strings for both the fuzzed JSON and fuzzed value. 13 | * 14 | * @return An empty {@code FuzzingResult}. 15 | */ 16 | public static FuzzingResult empty() { 17 | return new FuzzingResult("", ""); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/util/KeyValuePair.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | /** 8 | * A simple key-value pair class. 9 | * 10 | * @param The type of the key. 11 | * @param The type of the value. 12 | */ 13 | @Getter 14 | @Setter 15 | @EqualsAndHashCode(of = {"key", "value"}) 16 | public class KeyValuePair { 17 | private T key; 18 | private U value; 19 | 20 | /** 21 | * Constructs a key-value pair with the specified key and value. 22 | * 23 | * @param key The key of the key-value pair. 24 | * @param val The value of the key-value pair. 25 | */ 26 | public KeyValuePair(T key, U val) { 27 | this.key = key; 28 | this.value = val; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return key + "=" + value; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/util/LongTypeSerializer.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonPrimitive; 5 | import com.google.gson.JsonSerializationContext; 6 | import com.google.gson.JsonSerializer; 7 | 8 | import java.lang.reflect.Type; 9 | 10 | /** 11 | * Javascript is not very friendly with long numbers, so 12 | * we convert it to String. 13 | */ 14 | public class LongTypeSerializer implements JsonSerializer { 15 | @Override 16 | public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) { 17 | return new JsonPrimitive(String.valueOf(src)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/util/OffsetDatetimeTypeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import com.google.gson.TypeAdapter; 4 | import com.google.gson.stream.JsonReader; 5 | import com.google.gson.stream.JsonWriter; 6 | 7 | import java.io.IOException; 8 | import java.time.OffsetDateTime; 9 | import java.time.format.DateTimeFormatter; 10 | 11 | /** 12 | * This class is used to serialize and deserialize OffsetDateTime objects. 13 | */ 14 | public class OffsetDatetimeTypeAdapter extends TypeAdapter { 15 | 16 | private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_OFFSET_DATE_TIME; 17 | 18 | @Override 19 | public void write(JsonWriter out, OffsetDateTime value) throws IOException { 20 | out.value(value.format(FORMATTER)); 21 | } 22 | 23 | @Override 24 | public OffsetDateTime read(JsonReader in) throws IOException { 25 | return OffsetDateTime.parse(in.nextString(), FORMATTER); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/endava/cats/util/VersionProvider.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import picocli.CommandLine; 4 | 5 | import java.util.Properties; 6 | 7 | /** 8 | * Provides information about application version to PicoCli. 9 | */ 10 | public class VersionProvider implements CommandLine.IVersionProvider { 11 | 12 | @Override 13 | public String[] getVersion() throws Exception { 14 | Properties properties = new Properties(); 15 | properties.load(getClass().getClassLoader().getResourceAsStream("version.properties")); 16 | return new String[]{"%n@|green " + properties.getProperty("app.name") + " version " + 17 | properties.getProperty("app.version") + "|@"}; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/assets.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Endava/cats/5337ae1918b8d382b20c633c97c9cb3f3eda9d91/src/main/resources/assets.zip -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | # # # # # # # # # # # # # # # # # # # # # # # # # # 2 | # _____ ___ _____ _____ # 3 | # / __ \ / _ \_ _/ ___| # 4 | # | / \// /_\ \| | \ `--. # 5 | # | | | _ || | `--. \ # 6 | # | \__/\| | | || | /\__/ / # 7 | # \____/\_| |_/\_/ \____/ # 8 | # .. ... -.-. --- --- .-.. # 9 | # # 10 | # # # # # # # # # # # # # # # # # # # # # # # # # # -------------------------------------------------------------------------------- /src/main/resources/junit_summary.mustache: -------------------------------------------------------------------------------- 1 | 2 | 4 | {{#TEST_SUITES}} 5 | 7 | {{#testCases}} 8 | 9 | {{#warning}} 10 | WARN - {{resultReason}} - {{resultDetails}} 11 | {{/warning}} 12 | {{#error}} 13 | {{resultReason}} - {{resultDetails}} 14 | {{/error}} 15 | 16 | {{/testCases}} 17 | 18 | {{/TEST_SUITES}} 19 | -------------------------------------------------------------------------------- /src/main/resources/pl4j.properties: -------------------------------------------------------------------------------- 1 | pl4j.underline=false 2 | pl4j.use-markers=false 3 | pl4j.prefix-format=%1$-3s 4 | pl4j.show-labels=false -------------------------------------------------------------------------------- /src/main/resources/version.properties: -------------------------------------------------------------------------------- 1 | app.version=@project.version@ 2 | app.name=@project.name@ -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/args/UserArgumentsTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.args; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.io.File; 9 | 10 | @QuarkusTest 11 | class UserArgumentsTest { 12 | private UserArguments userArguments; 13 | 14 | @BeforeEach 15 | void setup() { 16 | userArguments = new UserArguments(); 17 | } 18 | 19 | @Test 20 | void shouldThrowExceptionWhenFileNotFound() { 21 | userArguments.words = new File("muhaha"); 22 | Assertions.assertThrows(RuntimeException.class, () -> userArguments.getWordsAsList()); 23 | } 24 | 25 | @Test 26 | void shouReturnFileContents() { 27 | userArguments.words = new File("src/test/resources/headers.yml"); 28 | org.assertj.core.api.Assertions.assertThat(userArguments.getWordsAsList()).contains("auth-header:"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/command/StatsCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.command; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.junit.jupiter.api.Test; 6 | import org.mockito.Mockito; 7 | import picocli.CommandLine; 8 | 9 | @QuarkusTest 10 | class StatsCommandTest { 11 | 12 | private StatsCommand statsCommand; 13 | 14 | @BeforeEach 15 | void setup() { 16 | statsCommand = new StatsCommand(); 17 | } 18 | 19 | @Test 20 | void shouldRunStats() { 21 | StatsCommand statsCommandSpy = Mockito.spy(statsCommand); 22 | CommandLine commandLine = new CommandLine(statsCommandSpy); 23 | commandLine.execute("--contract", "src/test/resources/openapi.yml"); 24 | Mockito.verify(statsCommandSpy, Mockito.times(1)).displayText(Mockito.any()); 25 | commandLine.execute("--contract", "src/test/resources/openapi.yml", "-j"); 26 | Mockito.verify(statsCommandSpy, Mockito.times(1)).displayJson(Mockito.any()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/fuzzer/fields/ZeroWidthCharsInValuesFieldsValidateSanitizeFuzzerTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.fuzzer.fields; 2 | 3 | import com.endava.cats.http.ResponseCodeFamilyPredefined; 4 | import io.quarkus.test.junit.QuarkusTest; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | @QuarkusTest 9 | class ZeroWidthCharsInValuesFieldsValidateSanitizeFuzzerTest { 10 | 11 | @Test 12 | void shouldReturn4XX() { 13 | ZeroWidthCharsInValuesFieldsValidateSanitizeFuzzer zwcf = new ZeroWidthCharsInValuesFieldsValidateSanitizeFuzzer(null, null, null); 14 | Assertions.assertThat(zwcf.getExpectedHttpCodeWhenRequiredFieldsAreFuzzed()).isEqualTo(ResponseCodeFamilyPredefined.FOURXX); 15 | Assertions.assertThat(zwcf.getExpectedHttpCodeWhenOptionalFieldsAreFuzzed()).isEqualTo(ResponseCodeFamilyPredefined.FOURXX); 16 | Assertions.assertThat(zwcf.getExpectedHttpCodeWhenFuzzedValueNotMatchesPattern()).isEqualTo(ResponseCodeFamilyPredefined.FOURXX); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/api/InvalidDataFormatTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import jakarta.inject.Inject; 6 | import org.assertj.core.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | 9 | @QuarkusTest 10 | class InvalidDataFormatTest { 11 | 12 | @Inject 13 | InvalidDataFormat invalidDataFormat; 14 | @Test 15 | void shouldReturnVoidWhenNoFormat() { 16 | Assertions.assertThat(invalidDataFormat.generator(new Schema<>(), null)).isInstanceOf(VoidGenerator.class); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/api/VoidGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.api; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | @QuarkusTest 9 | class VoidGeneratorTest { 10 | 11 | 12 | @Test 13 | void shouldGenerateNull() { 14 | VoidGenerator voidGenerator = new VoidGenerator(); 15 | Assertions.assertThat(voidGenerator.generate(new Schema<>())).isNull(); 16 | } 17 | 18 | @Test 19 | void shouldAlwaysApply() { 20 | VoidGenerator voidGenerator = new VoidGenerator(); 21 | Assertions.assertThat(voidGenerator.appliesTo("1", "2")).isTrue(); 22 | } 23 | 24 | @Test 25 | void shouldGenerateNullTotallyWrongValue() { 26 | VoidGenerator voidGenerator = new VoidGenerator(); 27 | Assertions.assertThat(voidGenerator.getTotallyWrongValue()).isNull(); 28 | } 29 | 30 | @Test 31 | void shouldGenerateNullAlmostWrongValue() { 32 | VoidGenerator voidGenerator = new VoidGenerator(); 33 | Assertions.assertThat(voidGenerator.getAlmostValidValue()).isNull(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/DateTimeGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class DateTimeGeneratorTest { 9 | @Test 10 | void givenADateTimeFormatGeneratorStrategy_whenGettingTheAlmostValidValue_thenTheValueIsReturnedAsExpected() { 11 | DateTimeGenerator strategy = new DateTimeGenerator(); 12 | Assertions.assertThat(strategy.getAlmostValidValue()).isEqualTo("2021-07-21-T10:22:1Z"); 13 | } 14 | 15 | 16 | @Test 17 | void givenADateTimeFormatGeneratorStrategy_whenGettingTheTotallyWrongValue_thenTheValueIsReturnedAsExpected() { 18 | DateTimeGenerator strategy = new DateTimeGenerator(); 19 | Assertions.assertThat(strategy.getTotallyWrongValue()).isEqualTo("1111-07-21T88:32:28Z"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/GenderGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class GenderGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | GenderGenerator genderGenerator = new GenderGenerator(); 16 | Assertions.assertThat(genderGenerator.generate(new Schema<>()).toString()).containsAnyOf("Male", "Female", "Other"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"gender,true", "other,false"}) 21 | void shouldApplyToFormat(String format, boolean expected) { 22 | GenderGenerator genderGenerator = new GenderGenerator(); 23 | Assertions.assertThat(genderGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | 26 | @ParameterizedTest 27 | @CsvSource({"gender,true", "GENDER,true", "other,false"}) 28 | void shouldApplyToPropertyName(String property, boolean expected) { 29 | GenderGenerator genderGenerator = new GenderGenerator(); 30 | Assertions.assertThat(genderGenerator.appliesTo("", property)).isEqualTo(expected); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/Gtin13GeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class Gtin13GeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | Gtin13Generator gtin13Generator = new Gtin13Generator(); 16 | Assertions.assertThat(gtin13Generator.generate(new Schema<>()).toString()).matches("[0-9]+").hasSize(13); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"gtin-13,not,true", "gtin13,not,true", "not,global-trade-item-number,true", "not,global-trade-number,true", "not,not,false", 21 | "ean13,not,true", "not,european-article-number,true"}) 22 | void shouldApply(String format, String property, boolean expected) { 23 | Gtin13Generator gtin13Generator = new Gtin13Generator(); 24 | Assertions.assertThat(gtin13Generator.appliesTo(format, property)).isEqualTo(expected); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/Gtin8GeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class Gtin8GeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | Gtin8Generator gtin8Generator = new Gtin8Generator(); 16 | Assertions.assertThat(gtin8Generator.generate(new Schema<>()).toString()).matches("[0-9]+").hasSize(8); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"ean8,true", "gtin8,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | Gtin8Generator gtin8Generator = new Gtin8Generator(); 23 | Assertions.assertThat(gtin8Generator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/IRIGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class IRIGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | IRIGenerator iriGenerator = new IRIGenerator(); 16 | Assertions.assertThat(iriGenerator.generate(new Schema<>()).toString()).startsWith("https://ë").endsWith(".com/cats"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"iri,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | IRIGenerator iriGenerator = new IRIGenerator(); 23 | Assertions.assertThat(iriGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/IRIReferenceGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class IRIReferenceGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | IRIReferenceGenerator iriReferenceGenerator = new IRIReferenceGenerator(); 16 | Assertions.assertThat(iriReferenceGenerator.generate(new Schema<>()).toString()).startsWith("/füzzing"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"iri-reference,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | IRIReferenceGenerator iriReferenceGenerator = new IRIReferenceGenerator(); 23 | Assertions.assertThat(iriReferenceGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/ISBN10GeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class ISBN10GeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | ISBN10Generator isbn10Generator = new ISBN10Generator(); 16 | Assertions.assertThat(isbn10Generator.generate(new Schema<>()).toString()).matches("[0-9]{10}"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"isbn10,not,true", "not,isbn10,true", "isbn,not,true", "not,isbn,true", "not,not,false"}) 21 | void shouldApply(String format, String property, boolean expected) { 22 | ISBN10Generator isbn10Generator = new ISBN10Generator(); 23 | Assertions.assertThat(isbn10Generator.appliesTo(format, property)).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/ISBN13GeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class ISBN13GeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | ISBN13Generator isbn13Generator = new ISBN13Generator(); 16 | Assertions.assertThat(isbn13Generator.generate(new Schema<>()).toString()).matches("[0-9]{13}"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"isbn13,not,true", "not,isbn13,true", "not,not,false"}) 21 | void shouldApply(String format, String property, boolean expected) { 22 | ISBN13Generator isbn13Generator = new ISBN13Generator(); 23 | Assertions.assertThat(isbn13Generator.appliesTo(format, property)).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/IbanGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class IbanGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | IbanGenerator ibanGenerator = new IbanGenerator(); 16 | Assertions.assertThat(ibanGenerator.generate(new Schema<>()).toString()).hasSizeGreaterThan(5); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"iban,true", "other,false"}) 21 | void shouldApplyToFormat(String format, boolean expected) { 22 | IbanGenerator ibanGenerator = new IbanGenerator(); 23 | Assertions.assertThat(ibanGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | 26 | @ParameterizedTest 27 | @CsvSource({"iban,true", "IBAN,true", "other#iban,true", "other, false"}) 28 | void shouldApplyToPropertyName(String property, boolean expected) { 29 | IbanGenerator ibanGenerator = new IbanGenerator(); 30 | Assertions.assertThat(ibanGenerator.appliesTo("", property)).isEqualTo(expected); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/IdnEmailGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class IdnEmailGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | IdnEmailGenerator idnEmailGenerator = new IdnEmailGenerator(); 16 | Assertions.assertThat(idnEmailGenerator.generate(new Schema<>()).toString()).endsWith("cööl.cats@cats.io"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"idn-email,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | IdnEmailGenerator idnEmailGenerator = new IdnEmailGenerator(); 23 | Assertions.assertThat(idnEmailGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/IdnHostnameGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class IdnHostnameGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | IdnHostnameGenerator hostnameGenerator = new IdnHostnameGenerator(); 16 | Assertions.assertThat(hostnameGenerator.generate(new Schema<>()).toString()).startsWith("www.ë").endsWith(".com"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"idn-hostname,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | IdnHostnameGenerator hostnameGenerator = new IdnHostnameGenerator(); 23 | Assertions.assertThat(hostnameGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/JsonPointerGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class JsonPointerGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | JsonPointerGenerator jsonPointerGenerator = new JsonPointerGenerator(); 16 | Assertions.assertThat(jsonPointerGenerator.generate(new Schema<>())).isEqualTo("/item/0/id"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"json-pointer,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | JsonPointerGenerator jsonPointerGenerator = new JsonPointerGenerator(); 23 | Assertions.assertThat(jsonPointerGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/KvPairsGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | import java.util.Map; 11 | 12 | @QuarkusTest 13 | class KvPairsGeneratorTest { 14 | @Test 15 | void shouldGenerate() { 16 | KvPairsGenerator kvPairsGenerator = new KvPairsGenerator(); 17 | Object generated = kvPairsGenerator.generate(new Schema<>()); 18 | Assertions.assertThat(generated).isInstanceOf(Map.class); 19 | } 20 | 21 | @ParameterizedTest 22 | @CsvSource({"kvpairs,true", "other,false"}) 23 | void shouldApply(String format, boolean expected) { 24 | KvPairsGenerator kvPairsGenerator = new KvPairsGenerator(); 25 | Assertions.assertThat(kvPairsGenerator.appliesTo(format, "")).isEqualTo(expected); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/PeriodGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | import java.time.Period; 11 | 12 | @QuarkusTest 13 | class PeriodGeneratorTest { 14 | 15 | @Test 16 | void shouldGenerate() { 17 | PeriodGenerator periodGenerator = new PeriodGenerator(); 18 | Assertions.assertThatNoException().isThrownBy(() -> Period.parse(periodGenerator.generate(new Schema<>()).toString())); 19 | } 20 | 21 | @ParameterizedTest 22 | @CsvSource({"period,true", "other,false"}) 23 | void shouldApply(String format, boolean expected) { 24 | PeriodGenerator periodGenerator = new PeriodGenerator(); 25 | Assertions.assertThat(periodGenerator.appliesTo(format, "")).isEqualTo(expected); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/RegexGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class RegexGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | RegexGenerator regexGenerator = new RegexGenerator(); 16 | Assertions.assertThat(regexGenerator.generate(new Schema<>())).isEqualTo("[a-z0-9]+"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"regex,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | RegexGenerator regexGenerator = new RegexGenerator(); 23 | Assertions.assertThat(regexGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/RelativeJsonPointerGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class RelativeJsonPointerGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | RelativeJsonPointerGenerator relativeJsonPointerGenerator = new RelativeJsonPointerGenerator(); 16 | Assertions.assertThat(relativeJsonPointerGenerator.generate(new Schema<>())).isEqualTo("1/id"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"relative-json-pointer,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | RelativeJsonPointerGenerator relativeJsonPointerGenerator = new RelativeJsonPointerGenerator(); 23 | Assertions.assertThat(relativeJsonPointerGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/StateGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class StateGeneratorTest { 12 | @Test 13 | void shouldGenerate() { 14 | StateGenerator stateGenerator = new StateGenerator(); 15 | Assertions.assertThat(stateGenerator.generate(new Schema<>()).toString()).hasSizeGreaterThan(1); 16 | } 17 | 18 | @ParameterizedTest 19 | @CsvSource({"state,true", "other,false"}) 20 | void shouldApplyToFormat(String format, boolean expected) { 21 | StateGenerator stateGenerator = new StateGenerator(); 22 | Assertions.assertThat(stateGenerator.appliesTo(format, "")).isEqualTo(expected); 23 | } 24 | 25 | @ParameterizedTest 26 | @CsvSource({"state,true", "STATE,true", "other#state,true", "statename,true", "other, false"}) 27 | void shouldApplyToPropertyName(String property, boolean expected) { 28 | StateGenerator stateGenerator = new StateGenerator(); 29 | Assertions.assertThat(stateGenerator.appliesTo("", property)).isEqualTo(expected); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/TimeGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | import java.time.OffsetTime; 11 | 12 | @QuarkusTest 13 | class TimeGeneratorTest { 14 | 15 | @ParameterizedTest 16 | @CsvSource({"time,true", "date-time,false"}) 17 | void shouldApply(String format, boolean expected) { 18 | TimeGenerator timeGenerator = new TimeGenerator(); 19 | Assertions.assertThat(timeGenerator.appliesTo(format, "")).isEqualTo(expected); 20 | } 21 | 22 | @Test 23 | void shouldGenerate() { 24 | TimeGenerator timeGenerator = new TimeGenerator(); 25 | Object generated = timeGenerator.generate(new Schema<>()); 26 | Assertions.assertThatNoException().isThrownBy(() -> OffsetTime.parse(generated.toString())); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/URIReferenceGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class URIReferenceGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | URIReferenceGenerator uriReferenceGenerator = new URIReferenceGenerator(); 16 | Assertions.assertThat(uriReferenceGenerator.generate(new Schema<>()).toString()).startsWith("/fuzzing"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"uri-reference,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | URIReferenceGenerator uriReferenceGenerator = new URIReferenceGenerator(); 23 | Assertions.assertThat(uriReferenceGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/URITemplateGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | @QuarkusTest 11 | class URITemplateGeneratorTest { 12 | 13 | @Test 14 | void shouldGenerate() { 15 | URITemplateGenerator uriTemplateGenerator = new URITemplateGenerator(); 16 | Assertions.assertThat(uriTemplateGenerator.generate(new Schema<>()).toString()).startsWith("/fuzzing").endsWith("/{path}"); 17 | } 18 | 19 | @ParameterizedTest 20 | @CsvSource({"uri-template,true", "other,false"}) 21 | void shouldApply(String format, boolean expected) { 22 | URITemplateGenerator uriTemplateGenerator = new URITemplateGenerator(); 23 | Assertions.assertThat(uriTemplateGenerator.appliesTo(format, "")).isEqualTo(expected); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/UUIDGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class UUIDGeneratorTest { 9 | @Test 10 | void givenAUUIDFormatGeneratorStrategy_whenGettingTheAlmostValidValue_thenTheValueIsReturnedAsExpected() { 11 | UUIDGenerator strategy = new UUIDGenerator(); 12 | Assertions.assertThat(strategy.getAlmostValidValue()).isEqualTo("123e4567-e89b-22d3-a456-426655440-92"); 13 | } 14 | 15 | @Test 16 | void givenAUUIDFormatGeneratorStrategy_whenGettingTheTotallyWrongValue_thenTheValueIsReturnedAsExpected() { 17 | UUIDGenerator strategy = new UUIDGenerator(); 18 | Assertions.assertThat(strategy.getTotallyWrongValue()).isEqualTo("123e4567"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/format/impl/UnixtimeGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.format.impl; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.media.Schema; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.CsvSource; 9 | 10 | import java.time.Instant; 11 | 12 | @QuarkusTest 13 | class UnixtimeGeneratorTest { 14 | 15 | @Test 16 | void shouldGenerate() { 17 | UnixtimeGenerator unixtimeGenerator = new UnixtimeGenerator(); 18 | Object generated = unixtimeGenerator.generate(new Schema<>()); 19 | Instant generatedInstant = Instant.ofEpochSecond((long) generated); 20 | Assertions.assertThat(generated).isInstanceOf(Long.class); 21 | Assertions.assertThat(generatedInstant).isBefore(Instant.now()); 22 | } 23 | 24 | @ParameterizedTest 25 | @CsvSource({"unixtime,true", "other,false"}) 26 | void shouldApply(String format, boolean expected) { 27 | UnixtimeGenerator unixtimeGenerator = new UnixtimeGenerator(); 28 | Assertions.assertThat(unixtimeGenerator.appliesTo(format, "")).isEqualTo(expected); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/simple/RegexGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.simple; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.util.regex.Pattern; 8 | 9 | @QuarkusTest 10 | class RegexGeneratorTest { 11 | 12 | @Test 13 | void shouldReturnDefaultWhenMaxLessThanZero() { 14 | String result = RegexGenerator.generate(Pattern.compile("test"), "test", 10, -10); 15 | 16 | Assertions.assertThat(result).isEqualTo(RegexGenerator.DEFAULT); 17 | } 18 | 19 | @Test 20 | void shouldReturnPrefixWhenPrefixMatchesPatternAndMinLessThanZero() { 21 | String result = RegexGenerator.generate(Pattern.compile("test"), "test", -10, 10); 22 | 23 | Assertions.assertThat(result).isEqualTo("test"); 24 | } 25 | 26 | @Test 27 | void shouldReturnDefaultWhenPrefixMatchesPatternButNotLength() { 28 | String result = RegexGenerator.generate(Pattern.compile("test"), "test", 10, 10); 29 | 30 | Assertions.assertThat(result).isEqualTo("DEFAULT_CATS"); 31 | } 32 | 33 | @Test 34 | void shouldGenerateFromRegexAndSize() { 35 | String result = RegexGenerator.generate(Pattern.compile("test+"), "test", 10, 10); 36 | 37 | Assertions.assertThat(result).isEqualTo("testtttttttttt"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/generator/simple/UnicodeGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.generator.simple; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class UnicodeGeneratorTest { 9 | 10 | @Test 11 | void shouldGenerateUnicodeMatchingPredicate() { 12 | String generated = UnicodeGenerator.generateRandomUnicodeString(10, Character::isISOControl); 13 | 14 | Assertions.assertThat(generated).matches(string -> string.chars().allMatch(Character::isISOControl)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/model/NoMediaTypeTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class NoMediaTypeTest { 9 | 10 | 11 | @Test 12 | void shouldReturnDefaultSchema() { 13 | Assertions.assertThat(new NoMediaType().getSchema().get$ref()).isEqualTo("#/components/schemas/empty_body"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/model/ProcessingErrorTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.model; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class ProcessingErrorTest { 9 | 10 | @Test 11 | void shouldIncludePath() { 12 | ProcessingError error = new ProcessingError("path", "GET", "message"); 13 | String result = error.toString(); 14 | Assertions.assertThat(result).isEqualTo("Path path, http method GET: message"); 15 | } 16 | 17 | @Test 18 | void shouldNotIncludePath() { 19 | ProcessingError error = new ProcessingError(null, "GET", "message"); 20 | String result = error.toString(); 21 | Assertions.assertThat(result).isEqualTo("http method GET: message"); 22 | } 23 | 24 | @Test 25 | void shouldNotIncludeHttpMethod() { 26 | ProcessingError error = new ProcessingError("path", null, "message"); 27 | String result = error.toString(); 28 | Assertions.assertThat(result).isEqualTo("Path path, message"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/strategy/NoopFuzzingStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class NoopFuzzingStrategyTest { 9 | 10 | @Test 11 | void givenAString_whenUsingTheNoopFuzzingStrategy_thenTheStringIsCorrectlyProcessed() { 12 | FuzzingStrategy strategy = FuzzingStrategy.noop().withData("inner"); 13 | 14 | Assertions.assertThat(strategy.process("string")).isEqualTo("string"); 15 | Assertions.assertThat(strategy.name()).isEqualTo("NOOP"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/strategy/PrefixFuzzingStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class PrefixFuzzingStrategyTest { 9 | 10 | @Test 11 | void givenAString_whenUsingThePrefixFuzzingStrategy_thenTheStringIsCorrectlyProcessed() { 12 | FuzzingStrategy strategy = FuzzingStrategy.prefix().withData("inner"); 13 | 14 | Assertions.assertThat(strategy.process("string")).isEqualTo("innerstring"); 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/strategy/ReplaceFuzzingStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class ReplaceFuzzingStrategyTest { 9 | 10 | @Test 11 | void givenAString_whenUsingTheReplaceFuzzingStrategy_thenTheStringIsCorrectlyProcessed() { 12 | FuzzingStrategy strategy = FuzzingStrategy.replace().withData("inner"); 13 | 14 | Assertions.assertThat(strategy.process("string")).isEqualTo("inner"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/strategy/SkipFuzzingStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class SkipFuzzingStrategyTest { 9 | 10 | @Test 11 | void givenAString_whenUsingTheSkipFuzzingStrategy_thenTheStringIsCorrectlyProcessed() { 12 | FuzzingStrategy strategy = FuzzingStrategy.skip().withData("inner"); 13 | 14 | Assertions.assertThat(strategy.process("string")).isEqualTo("inner"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/strategy/TrailFuzzingStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.strategy; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | @QuarkusTest 8 | class TrailFuzzingStrategyTest { 9 | @Test 10 | void givenAString_whenUsingTheTrailFuzzingStrategy_thenTheStringIsCorrectlyProcessed() { 11 | FuzzingStrategy strategy = FuzzingStrategy.trail().withData("inner"); 12 | 13 | Assertions.assertThat(strategy.process("string")).isEqualTo("stringinner"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/util/GlobalLoggingExtension.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import io.github.ludovicianul.prettylogger.PrettyLogger; 4 | import io.github.ludovicianul.prettylogger.config.level.PrettyLevel; 5 | import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback; 6 | import io.quarkus.test.junit.callback.QuarkusTestMethodContext; 7 | 8 | public class GlobalLoggingExtension implements QuarkusTestBeforeEachCallback { 9 | 10 | @Override 11 | public void beforeEach(QuarkusTestMethodContext context) { 12 | CatsUtil.setCatsLogLevel("ALL"); 13 | PrettyLogger.enableLevels(PrettyLevel.STAR, PrettyLevel.NONE, PrettyLevel.INFO, PrettyLevel.TIMER, PrettyLevel.FATAL); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/util/KeyValueSerializerTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import com.google.gson.JsonElement; 4 | import io.quarkus.test.junit.QuarkusTest; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.util.Set; 9 | 10 | @QuarkusTest 11 | class KeyValueSerializerTest { 12 | 13 | @Test 14 | void shouldMaskValue() { 15 | KeyValueSerializer keyValueSerializer = new KeyValueSerializer(Set.of("header1")); 16 | JsonElement element = keyValueSerializer.serialize(new KeyValuePair<>("header1", "myValue"), KeyValuePair.class, null); 17 | Assertions.assertThat(element.toString()).contains("$$header1").doesNotContain("myValue"); 18 | } 19 | 20 | @Test 21 | void shouldNotMaskValue() { 22 | KeyValueSerializer keyValueSerializer = new KeyValueSerializer(Set.of("notMasked")); 23 | JsonElement element = keyValueSerializer.serialize(new KeyValuePair<>("header1", "myValue"), KeyValuePair.class, null); 24 | Assertions.assertThat(element.toString()).contains("myValue").doesNotContain("$$header1"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/util/LongTypeSerializerTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import com.google.gson.JsonElement; 4 | import io.quarkus.test.junit.QuarkusTest; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | @QuarkusTest 9 | class LongTypeSerializerTest { 10 | 11 | @Test 12 | void shouldSerializeLongAsString() { 13 | LongTypeSerializer serializer = new LongTypeSerializer(); 14 | JsonElement element = serializer.serialize(10L, Long.class, null); 15 | Assertions.assertThat(element.getAsString()).isEqualTo("10"); 16 | Assertions.assertThat(element.getAsLong()).isEqualTo(10L); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/util/OpenApiParseResultTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import io.swagger.v3.oas.models.SpecVersion; 5 | import org.assertj.core.api.Assertions; 6 | import org.junit.jupiter.params.ParameterizedTest; 7 | import org.junit.jupiter.params.provider.CsvSource; 8 | 9 | @QuarkusTest 10 | class OpenApiParseResultTest { 11 | 12 | @ParameterizedTest 13 | @CsvSource({"V30,V30", "V31,V31"}) 14 | void shouldProperlyParseVersion(SpecVersion specVersion, OpenApiParseResult.OpenApiVersion expected) { 15 | OpenApiParseResult.OpenApiVersion result = OpenApiParseResult.OpenApiVersion.fromSwaggerVersion(specVersion); 16 | Assertions.assertThat(result).isEqualTo(expected); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/endava/cats/util/WordUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.endava.cats.util; 2 | 3 | import io.quarkus.test.junit.QuarkusTest; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.util.Set; 8 | 9 | @QuarkusTest 10 | class WordUtilsTest { 11 | 12 | @Test 13 | void shouldReturnAllCombinations() { 14 | String[] words = new String[]{"pet", "name", "id"}; 15 | Set result = WordUtils.createWordCombinations(words); 16 | 17 | Assertions.assertThat(result).containsOnly("ID", "Id", "NAME-ID", "NAMEID", "NAME_ID", "Name-Id", "NameId", 18 | "Name_Id", "PET-NAME-ID", "PETNAMEID", "PET_NAME_ID", "Pet-Name-Id", "PetNameId", "Pet_Name_Id", 19 | "id", "name-Id", "name-id", "nameId", "name_Id", "name_id", "nameid", "pet-Name-Id", "pet-name-id", "petNameId", "pet_Name_Id", "pet_name_id", "petnameid"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback: -------------------------------------------------------------------------------- 1 | com.endava.cats.util.GlobalLoggingExtension -------------------------------------------------------------------------------- /src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | quarkus.application.version=1 2 | quarkus.application.name=cats 3 | app.timestamp=2020-01-01 4 | quarkus.log.level=WARN 5 | quarkus.log.category."org.jline".level=OFF 6 | quarkus.banner.path=banner.txt 7 | quarkus.log.console.format=[%X{id_ansi}][%X{fuzzer}] %m %n -------------------------------------------------------------------------------- /src/test/resources/cats.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Endava/cats/5337ae1918b8d382b20c633c97c9cb3f3eda9d91/src/test/resources/cats.jks -------------------------------------------------------------------------------- /src/test/resources/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "person": { 3 | "name": "John Doe", 4 | "age": 30, 5 | "address": { 6 | "street": "123 Main St", 7 | "city": "New York", 8 | "zip": "10001" 9 | } 10 | }, 11 | "company": { 12 | "name": "Acme Inc", 13 | "employees": [ 14 | { 15 | "name": "Alice", 16 | "position": "Manager" 17 | }, 18 | { 19 | "name": "Bob", 20 | "position": "Developer" 21 | } 22 | ], 23 | "location": { 24 | "country": "USA", 25 | "city": "San Francisco" 26 | } 27 | }, 28 | "products": [ 29 | { 30 | "name": "Widget", 31 | "price": 19.99 32 | }, 33 | { 34 | "name": "Gadget", 35 | "price": 29.99 36 | } 37 | ], 38 | "tags": [ 39 | "tech", 40 | "gadgets", 41 | "electronics" 42 | ], 43 | "isActive": true, 44 | "creationDate": "2024-04-05T12:00:00Z" 45 | } 46 | -------------------------------------------------------------------------------- /src/test/resources/dict.txt: -------------------------------------------------------------------------------- 1 | test1 2 | test2 -------------------------------------------------------------------------------- /src/test/resources/duplicate-operationids.yml: -------------------------------------------------------------------------------- 1 | info: 2 | description: "" 3 | title: "" 4 | version: "" 5 | openapi: 3.0.1 6 | paths: 7 | /users/{userId}: 8 | post: 9 | operationId: createUser 10 | requestBody: 11 | content: 12 | application/json: 13 | schema: 14 | $ref: '#/components/schemas/User' 15 | responses: 16 | '200': 17 | description: OK 18 | content: 19 | application/json: 20 | schema: 21 | $ref: '#/components/schemas/User' 22 | get: 23 | operationId: createUser 24 | responses: 25 | '200': 26 | description: OK 27 | content: 28 | application/json: 29 | schema: 30 | $ref: '#/components/schemas/User' 31 | delete: 32 | operationId: deleteUser 33 | responses: 34 | '200': 35 | description: OK 36 | content: 37 | application/json: 38 | schema: 39 | $ref: '#/components/schemas/User' 40 | components: 41 | schemas: 42 | User: 43 | type: object 44 | properties: 45 | id: 46 | type: integer 47 | name: 48 | type: string -------------------------------------------------------------------------------- /src/test/resources/empty-paths.yml: -------------------------------------------------------------------------------- 1 | info: 2 | description: "" 3 | title: "" 4 | version: "" 5 | openapi: 3.0.1 6 | paths: 7 | /users/{userId}: -------------------------------------------------------------------------------- /src/test/resources/empty.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Endava/cats/5337ae1918b8d382b20c633c97c9cb3f3eda9d91/src/test/resources/empty.yml -------------------------------------------------------------------------------- /src/test/resources/error_leaks.txt: -------------------------------------------------------------------------------- 1 | this is an error leak 2 | which is very bad -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-additional.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | pet: 5 | - stay 6 | expectedResponseCode: 200 7 | httpMethod: POST 8 | oneOfSelection: 9 | test#test: "mumu" 10 | additionalProperties_1: 11 | topElement: "metadata" 12 | mapValues: 13 | "test": "value1" 14 | "anotherTest": "value2" 15 | additionalProperties_2: 16 | topElement: "otherElement" 17 | mapValues: 18 | "test": "different" 19 | "anotherTest": "anotherDifferent" 20 | output: 21 | resp: code -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-array-iterate.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Create a new Key 4 | pet: [ "dog","cat" ] 5 | httpMethod: POST 6 | expectedResponseCode: 2XX 7 | verify: 8 | $.size(): 0 -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-array-replace.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Create a new Key 4 | key_ops: [ "sign","verify" ] 5 | httpMethod: POST 6 | expectedResponseCode: 2XX 7 | verify: 8 | $.size(): 0 -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-http-method.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | httpMethod: HEAD 5 | pet: 6 | - stay 7 | expectedResponseCode: 200 8 | oneOfSelection: 9 | test#test: "mumu" 10 | output: 11 | resp: code 12 | verify: 13 | name#first: "Cats" 14 | address: "25 street" -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-multiple-rp.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | name: john 5 | pet: 6 | - stay 7 | - at 8 | - home 9 | expectedResponseCode: 10 | - 200 11 | - 400 12 | httpMethod: POST 13 | output: 14 | resp: code 15 | custId: ${request#name} 16 | test_2: 17 | description: Second Test Case 18 | httpMethod: POST 19 | pet: ${resp} 20 | expectedResponseCode: 200 21 | /other-pet: 22 | test_2: 23 | description: Another Pet Endpoint not matching syntax 24 | httpMethod: POST -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-no-resp-code.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | httpMethod: POST 5 | pet: 6 | - stay 7 | expectedResponseCode: 400 8 | oneOfSelection: 9 | test#test: "mumu" 10 | output: 11 | resp: code 12 | -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-req-verify.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | pet: myPet 5 | expectedResponseCode: 200 6 | httpMethod: POST 7 | output: 8 | resp: code 9 | verify: 10 | name#first: "Cats" 11 | id: 25 12 | petName: ${request.pet} 13 | test_2: 14 | description: Second Test Case 15 | pet: ${resp} 16 | httpMethod: POST 17 | expectedResponseCode: 200 18 | /other-pet: 19 | test_2: 20 | description: Another Pet Endpoint not matching syntax -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-resp-code-family-verify.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | httpMethod: POST 5 | pet: 6 | - stay 7 | expectedResponseCode: 2XX 8 | oneOfSelection: 9 | test#test: "mumu" 10 | output: 11 | resp: code 12 | verify: 13 | code: 200 -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-resp-code-family.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | httpMethod: POST 5 | pet: 6 | - stay 7 | expectedResponseCode: 2XX 8 | oneOfSelection: 9 | test#test: "mumu" 10 | output: 11 | resp: code -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-resp-code-verify.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | httpMethod: POST 5 | pet: 6 | - stay 7 | expectedResponseCode: 400 8 | oneOfSelection: 9 | test#test: "mumu" 10 | output: 11 | resp: code 12 | verify: 13 | code: 200 -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-verify-not-set.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | pet: 5 | - stay 6 | expectedResponseCode: 200 7 | httpMethod: POST 8 | output: 9 | resp: code 10 | verify: 11 | name#first: "Cats" 12 | address: "25 street" 13 | test_2: 14 | description: Second Test Case 15 | pet: ${resp} 16 | expectedResponseCode: 200 17 | /other-pet: 18 | test_2: 19 | description: Another Pet Endpoint not matching syntax -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer-verify.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | pet: 5 | - stay 6 | - at 7 | - home 8 | expectedResponseCode: 200 9 | httpMethod: POST 10 | output: 11 | resp: code 12 | verify: 13 | name#first: $request#name 14 | id: 25 15 | $#length(): 3 16 | checkBoolean: T(java.time.LocalDate).now().isAfter(T(java.time.LocalDate).parse(expiry.toString())) 17 | checkTrue: T(java.time.LocalDate).now().isAfter(T(java.time.LocalDate).parse(expiry.toString())) 18 | checkFalse: T(java.time.LocalDate).now().isBefore(T(java.time.LocalDate).parse(expiry.toString())) 19 | checkTrue_2: T(java.time.LocalDate).now().isAfter(T(java.time.LocalDate).parse(expiry.toString())) 20 | test_2: 21 | description: Second Test Case 22 | pet: ${resp} 23 | httpMethod: POST 24 | expectedResponseCode: 200 25 | /other-pet: 26 | test_2: 27 | description: Another Pet Endpoint not matching syntax -------------------------------------------------------------------------------- /src/test/resources/functionalFuzzer.yml: -------------------------------------------------------------------------------- 1 | /pets/{id}/move: 2 | test_1: 3 | description: Simple Test Case 4 | name: john 5 | pet: 6 | - stay 7 | - at 8 | - home 9 | expectedResponseCode: 200 10 | httpMethod: POST 11 | output: 12 | resp: code 13 | custId: ${request#name} 14 | test_2: 15 | description: Second Test Case 16 | httpMethod: POST 17 | pet: ${resp} 18 | expectedResponseCode: 200 19 | /other-pet: 20 | test_2: 21 | description: Another Pet Endpoint not matching syntax 22 | httpMethod: POST -------------------------------------------------------------------------------- /src/test/resources/fuzzConfig.properties: -------------------------------------------------------------------------------- 1 | DummyAcceptHeaders.expectedResponseCode=403 2 | 3 | -------------------------------------------------------------------------------- /src/test/resources/headers.yml: -------------------------------------------------------------------------------- 1 | All: 2 | header: value 3 | catsFuzzedHeader: cats 4 | auth-header: 5 | jwt: value -------------------------------------------------------------------------------- /src/test/resources/mutators/first.yml: -------------------------------------------------------------------------------- 1 | name: xss mutator 2 | type: replace 3 | values: 4 | - "