Add XML domain and documentation This change introduces a new FuzzTest domain for generating complex XML strings. It includes: - An XML domain implementation (`fuzztest/internal/domains/xml_domain.h`) that uses `DomainBuilder` for recursion and helper domains for tags, attributes, and content. - An example fuzz test (`examples/xml_fuzz_test.cc`) demonstrating how to use the XML domain. - A new documentation file (`doc/xml_domain.md`) explaining the design and usage of the XML domain. The example fuzz test's BUILD file uses `cc_test` as a workaround for potential Bazel issues with `cc_fuzz_test`. The documentation includes a note about this.
diff --git a/.hypothesis/constants/17dd46dc7a458a66 b/.hypothesis/constants/17dd46dc7a458a66 new file mode 100644 index 0000000..545b5aa --- /dev/null +++ b/.hypothesis/constants/17dd46dc7a458a66
@@ -0,0 +1,4 @@ +# file: /app/xpath_validator/src/xpath_validator/domain/xml_domain.py +# hypothesis_version: 6.135.6 + +['L', 'N', 'P', 'S', 'Z', '__main__', 'a', 'z'] \ No newline at end of file
diff --git a/.hypothesis/constants/da39a3ee5e6b4b0d b/.hypothesis/constants/da39a3ee5e6b4b0d new file mode 100644 index 0000000..38e5344 --- /dev/null +++ b/.hypothesis/constants/da39a3ee5e6b4b0d
@@ -0,0 +1,4 @@ +# file: /usr/lib/python3.10/sitecustomize.py +# hypothesis_version: 6.135.6 + +[] \ No newline at end of file
diff --git a/.hypothesis/unicode_data/13.0.0/charmap.json.gz b/.hypothesis/unicode_data/13.0.0/charmap.json.gz new file mode 100644 index 0000000..a7c6200 --- /dev/null +++ b/.hypothesis/unicode_data/13.0.0/charmap.json.gz Binary files differ
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000..43e8b2c --- /dev/null +++ b/MODULE.bazel.lock
@@ -0,0 +1,217 @@ +{ + "lockFileVersion": 18, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-py/2.1.0/MODULE.bazel": "5ebe5bf853769c65707e5c28f216798f7a4b1042015e6a36e6d03094d94bec8a", + "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b", + "https://bcr.bazel.build/modules/antlr4-cpp-runtime/4.12.0/MODULE.bazel": "5456a3ccfd57186adf742190961b4aa07aab86f772a3eb4ce241f7254869fc86", + "https://bcr.bazel.build/modules/antlr4-cpp-runtime/4.12.0/source.json": "b56033b603cf951d4063c805e8cb48bfa81dc019bd046dbbea7815fdd906a81d", + "https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896", + "https://bcr.bazel.build/modules/apple_support/1.13.0/MODULE.bazel": "7c8cdea7e031b7f9f67f0b497adf6d2c6a2675e9304ca93a9af6ed84eef5a524", + "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85", + "https://bcr.bazel.build/modules/apple_support/1.15.1/source.json": "517f2b77430084c541bc9be2db63fdcbb7102938c5f64c17ee60ffda2e5cf07b", + "https://bcr.bazel.build/modules/aspect_bazel_lib/1.31.2/MODULE.bazel": "7bee702b4862612f29333590f4b658a5832d433d6f8e4395f090e8f4e85d442f", + "https://bcr.bazel.build/modules/aspect_bazel_lib/1.38.0/MODULE.bazel": "6307fec451ba9962c1c969eb516ebfe1e46528f7fa92e1c9ac8646bef4cdaa3f", + "https://bcr.bazel.build/modules/aspect_bazel_lib/1.40.3/MODULE.bazel": "668e6bcb4d957fc0e284316dba546b705c8d43c857f87119619ee83c4555b859", + "https://bcr.bazel.build/modules/aspect_bazel_lib/1.40.3/source.json": "f5a28b1320e5f444e798b4afc1465c8b720bfaec7522cca38a23583dffe85e6d", + "https://bcr.bazel.build/modules/aspect_rules_js/1.33.1/MODULE.bazel": "db3e7f16e471cf6827059d03af7c21859e7a0d2bc65429a3a11f005d46fc501b", + "https://bcr.bazel.build/modules/aspect_rules_js/1.39.0/MODULE.bazel": "aece421d479e3c31dc3e5f6d49a12acc2700457c03c556650ec7a0ff23fc0d95", + "https://bcr.bazel.build/modules/aspect_rules_js/1.39.0/source.json": "a8f93e4ad8843e8aa407fa5fd7c8b63a63846c0ce255371ff23384582813b13d", + "https://bcr.bazel.build/modules/aspect_rules_lint/0.12.0/MODULE.bazel": "e767c5dbfeb254ec03275a7701b5cfde2c4d2873676804bc7cb27ddff3728fed", + "https://bcr.bazel.build/modules/aspect_rules_lint/0.12.0/source.json": "9a3668e1ee219170e22c0e7f3ab959724c6198fdd12cd503fa10b1c6923a2559", + "https://bcr.bazel.build/modules/bazel_features/0.1.0/MODULE.bazel": "47011d645b0f949f42ee67f2e8775188a9cf4a0a1528aa2fa4952f2fd00906fd", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", + "https://bcr.bazel.build/modules/bazel_features/1.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a", + "https://bcr.bazel.build/modules/bazel_features/1.23.0/source.json": "c72c61b722d7c3f884994fe647afeb2ed1ae66c437f8f370753551f7b4d8be7f", + "https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/boringssl/0.0.0-20240530-2db0eb3/MODULE.bazel": "d0405b762c5e87cd445b7015f2b8da5400ef9a8dbca0bfefa6c1cea79d528a97", + "https://bcr.bazel.build/modules/boringssl/0.0.0-20240530-2db0eb3/source.json": "0d413869349e82e5d679802abe9ce23e0326bbf56daa97ae9e7dbdcec72982fc", + "https://bcr.bazel.build/modules/brotli/1.1.0/MODULE.bazel": "3b5b90488995183419c4b5c9b063a164f6c0bc4d0d6b40550a612a5e860cc0fe", + "https://bcr.bazel.build/modules/brotli/1.1.0/source.json": "098a4fd315527166e8dfe1fd1537c96a737a83764be38fc43f4da231d600f3d0", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/bzip2/1.0.8/MODULE.bazel": "83ee443b286b0b91566e5ee77e74ba6445895f3135467893871560f9e4ebc159", + "https://bcr.bazel.build/modules/bzip2/1.0.8/source.json": "b64f3a2f973749cf5f6ee32b3d804af56a35a746228a7845ed5daa31c8cc8af1", + "https://bcr.bazel.build/modules/gazelle/0.27.0/MODULE.bazel": "3446abd608295de6d90b4a8a118ed64a9ce11dcb3dda2dc3290a22056bd20996", + "https://bcr.bazel.build/modules/gazelle/0.30.0/MODULE.bazel": "f888a1effe338491f35f0e0e85003b47bb9d8295ccba73c37e07702d8d31c65b", + "https://bcr.bazel.build/modules/gazelle/0.30.0/source.json": "7af0779f99120aafc73be127615d224f26da2fc5a606b52bdffb221fd9efb737", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.16.0/MODULE.bazel": "a175623c69e94fca4ca7acbc12031e637b0c489318cd4805606981d4d7adb34a", + "https://bcr.bazel.build/modules/googletest/1.16.0/source.json": "dd011b202542efcd4c0e3df34b1558d41598c6f287846728315ded5f7984b77a", + "https://bcr.bazel.build/modules/highwayhash/0.0.0-20240305-5ad3bf8/MODULE.bazel": "5c7f29d5bd70feff14b0f65b39584957e18e4a8d555e5a29a4c36019afbb44b9", + "https://bcr.bazel.build/modules/highwayhash/0.0.0-20240305-5ad3bf8/source.json": "211c0937ef5f537da6c3c135d12e60927c71b380642e207e4a02b86d29c55e85", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", + "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", + "https://bcr.bazel.build/modules/lz4/1.9.4/MODULE.bazel": "e3d307b1d354d70f6c809167eafecf5d622c3f27e3971ab7273410f429c7f83a", + "https://bcr.bazel.build/modules/lz4/1.9.4/source.json": "233f0bdfc21f254e3dda14683ddc487ca68c6a3a83b7d5db904c503f85bd089b", + "https://bcr.bazel.build/modules/nlohmann_json/3.11.3/MODULE.bazel": "87023db2f55fc3a9949c7b08dc711fae4d4be339a80a99d04453c4bb3998eefc", + "https://bcr.bazel.build/modules/nlohmann_json/3.11.3/source.json": "296c63a90c6813e53b3812d24245711981fc7e563d98fe15625f55181494488a", + "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.10/source.json": "f22828ff4cf021a6b577f1bf6341cb9dcd7965092a439f64fc1bb3b7a5ae4bd5", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a", + "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/28.3/MODULE.bazel": "2b3764bbab2e46703412bd3b859efcf0322638ed015e88432df3bb740507a1e9", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/protobuf/30.2/MODULE.bazel": "6b8b37f8390fbaf9bee5eed558697238082fab658a8a8996328628292ae79d2e", + "https://bcr.bazel.build/modules/protobuf/30.2/source.json": "7d7f541c637b49edbefa5aeca2cc365f2e3edac8d75fedb448d68ea003d9ded7", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34", + "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/MODULE.bazel": "b4963dda9b31080be1905ef085ecd7dd6cd47c05c79b9cdf83ade83ab2ab271a", + "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/source.json": "2ff292be6ef3340325ce8a045ecc326e92cbfab47c7cbab4bd85d28971b97ac4", + "https://bcr.bazel.build/modules/re2/2024-07-02/MODULE.bazel": "0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa", + "https://bcr.bazel.build/modules/riegeli/0.0.0-20241218-3385e3c/MODULE.bazel": "14bbe297ac80b30b689bde824d823f53bd87cd504ec3f82de72a730e7b02d526", + "https://bcr.bazel.build/modules/riegeli/0.0.0-20241218-3385e3c/source.json": "c3c4c0524f8afcfd6fbd0d3d212d4589fd9f26635dd0bcf20e5acc87493ab362", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_apple/3.13.0/MODULE.bazel": "b4559a2c6281ca3165275bb36c1f0ac74666632adc5bdb680e366de7ce845f43", + "https://bcr.bazel.build/modules/rules_apple/3.13.0/source.json": "fe31c678e2256daa91a802664b578c1de71dc43a49a7ccc16db001378f312cd3", + "https://bcr.bazel.build/modules/rules_buf/0.1.1/MODULE.bazel": "6189aec18a4f7caff599ad41b851ab7645d4f1e114aa6431acf9b0666eb92162", + "https://bcr.bazel.build/modules/rules_buf/0.1.1/source.json": "021363d254f7438f3f10725355969c974bb2c67e0c28667782ade31a9cdb747f", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/source.json": "4db99b3f55c90ab28d14552aa0632533e3e8e5e9aea0f5c24ac0014282c2a7c5", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_go/0.33.0/MODULE.bazel": "a2b11b64cd24bf94f57454f53288a5dacfe6cb86453eee7761b7637728c1910c", + "https://bcr.bazel.build/modules/rules_go/0.38.1/MODULE.bazel": "fb8e73dd3b6fc4ff9d260ceacd830114891d49904f5bda1c16bc147bcc254f71", + "https://bcr.bazel.build/modules/rules_go/0.39.1/MODULE.bazel": "d34fb2a249403a5f4339c754f1e63dc9e5ad70b47c5e97faee1441fc6636cd61", + "https://bcr.bazel.build/modules/rules_go/0.39.1/source.json": "f21e042154010ae2c944ab230d572b17d71cdb27c5255806d61df6ccaed4354c", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", + "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel": "30d9135a2b6561c761bd67bd4990da591e6bdc128790ce3e7afd6a3558b2fb64", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.11.0/MODULE.bazel": "c3d280bc5ff1038dcb3bacb95d3f6b83da8dd27bba57820ec89ea4085da767ad", + "https://bcr.bazel.build/modules/rules_java/8.11.0/source.json": "302b52a39259a85aa06ca3addb9787864ca3e03b432a5f964ea68244397e7544", + "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", + "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", + "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", + "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/0.0.8/MODULE.bazel": "5669c6fe49b5134dbf534db681ad3d67a2d49cfc197e4a95f1ca2fd7f3aebe96", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_nodejs/5.8.2/MODULE.bazel": "6bc03c8f37f69401b888023bf511cb6ee4781433b0cb56236b2e55a21e3a026a", + "https://bcr.bazel.build/modules/rules_nodejs/5.8.2/source.json": "6e82cf5753d835ea18308200bc79b9c2e782efe2e2a4edc004a9162ca93382ca", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96", + "https://bcr.bazel.build/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937", + "https://bcr.bazel.build/modules/rules_python/0.36.0/MODULE.bazel": "a4ce1ccea92b9106c7d16ab9ee51c6183107e78ba4a37aa65055227b80cd480c", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43", + "https://bcr.bazel.build/modules/rules_python/1.0.0/source.json": "b0162a65c6312e45e7912e39abd1a7f8856c2c7e41ecc9b6dc688a6f6400a917", + "https://bcr.bazel.build/modules/rules_rust/0.45.1/MODULE.bazel": "a69d0db3a958fab2c6520961e1b2287afcc8b36690fd31bbc4f6f7391397150d", + "https://bcr.bazel.build/modules/rules_rust/0.51.0/MODULE.bazel": "2b6d1617ac8503bfdcc0e4520c20539d4bba3a691100bee01afe193ceb0310f9", + "https://bcr.bazel.build/modules/rules_rust/0.51.0/source.json": "79a530199d9826a93b31d05b7d9b39dc753a80f88856d3ca5376f665a82cc5e6", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/source.json": "7f27af3c28037d9701487c4744b5448d26537cc66cdef0d8df7ae85411f8de95", + "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca", + "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046", + "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186", + "https://bcr.bazel.build/modules/snappy/1.2.0/MODULE.bazel": "cc7a727b46089c7fdae0ede21b1fd65bdb14d01823da118ef5c48044f40b6b27", + "https://bcr.bazel.build/modules/snappy/1.2.0/source.json": "17f5527e15d30a9d9eebf79ed73b280b56cac44f8c8fea696666d99943f84c33", + "https://bcr.bazel.build/modules/stardoc/0.5.0/MODULE.bazel": "f9f1f46ba8d9c3362648eea571c6f9100680efc44913618811b58cc9c02cd678", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.4/MODULE.bazel": "6569966df04610b8520957cb8e97cf2e9faac2c0309657c537ab51c16c18a2a4", + "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", + "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", + "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", + "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/source.json": "32bd87e5f4d7acc57c5b2ff7c325ae3061d5e242c0c4c214ae87e0f1c13e54cb", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.1/MODULE.bazel": "c037f75fa1b7e1ff15fbd15d807a8ce545e9b02f02df0a9777aa9aa7d8b268bb", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.1/source.json": "766f28499a16fa9ed8dc94382d50e80ceda0d0ab80b79b7b104a67074ab10e1f", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198", + "https://bcr.bazel.build/modules/zstd/1.5.6/MODULE.bazel": "471ebe7d3cdd8c6469390fcf623eb4779ff55fbee0a87f1dc57a1def468b96d4", + "https://bcr.bazel.build/modules/zstd/1.5.6/source.json": "02010c3333fc89b44fe861db049968decb6e688411f7f9d4f6791d74f9adfb51" + }, + "selectedYankedVersions": {}, + "moduleExtensions": {} +}
diff --git a/doc/xml_domain.md b/doc/xml_domain.md new file mode 100644 index 0000000..0288284 --- /dev/null +++ b/doc/xml_domain.md
@@ -0,0 +1,267 @@ +# XML Domain + +## Purpose + +The XML domain in FuzzTest is designed to generate well-formed XML (Extensible Markup Language) strings. These strings can be used as inputs for fuzz testing software that parses or processes XML data. By generating a wide variety of valid and complex XML structures, this domain helps uncover potential vulnerabilities, bugs, or unexpected behaviors in XML-handling code. + +## Design + +The XML domain is built using several components of the FuzzTest library, centered around the `XmlElement` class and the `XmlElementDomain` function. + +### `XmlElement` Structure + +The core of the XML generation is the `XmlElement` class, which represents a single XML element. It's defined to hold the tag name, attributes, and content of an element. The content itself can be either a simple text string or a vector of child `XmlElement` objects, allowing for recursive, nested structures. + +```cpp +// Located in: fuzztest/internal/domains/xml_domain.h + +#include <string> +#include <vector> +#include <map> +#include <variant> // Required for std::variant +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" + +namespace fuzztest::internal { + +// Forward declaration +class XmlElement; + +// Define content type: can be a string (text) or a vector of child XmlElements +using XmlContentType = std::variant<std::string, std::vector<XmlElement>>; + +// Represents an XML element. +class XmlElement { + public: + std::string tag_name; + std::map<std::string, std::string> attributes; + XmlContentType content; + + XmlElement() = default; + XmlElement(std::string tag, std::map<std::string, std::string> attrs, XmlContentType cont) + : tag_name(std::move(tag)), attributes(std::move(attrs)), content(std::move(cont)) {} + + // Function to serialize the XmlElement to a string + std::string ToString() const { + std::string attrs_str; + for (const auto& attr : attributes) { + attrs_str += absl::StrCat(" ", attr.first, "=\"", attr.second, "\""); + } + + std::string content_str; + if (std::holds_alternative<std::string>(content)) { + content_str = std::get<std::string>(content); + } else if (std::holds_alternative<std::vector<XmlElement>>(content)) { + for (const auto& child : std::get<std::vector<XmlElement>>(content)) { + content_str += child.ToString(); + } + } + return absl::StrCat("<", tag_name, attrs_str, ">", content_str, "</", tag_name, ">"); + } + + template <typename Sink> + friend void AbslStringify(Sink& sink, const XmlElement& element) { + std::string attrs_str_repr; + for (const auto& attr : element.attributes) { + if (!attrs_str_repr.empty()) attrs_str_repr += ", "; + attrs_str_repr += absl::StrCat(attr.first, "=", attr.second); + } + + std::string content_repr; + if (std::holds_alternative<std::string>(element.content)) { + content_repr = absl::StrCat("\"", std::get<std::string>(element.content), "\""); + } else if (std::holds_alternative<std::vector<XmlElement>>(element.content)) { + content_repr = absl::StrCat("[", absl::StrJoin(std::get<std::vector<XmlElement>>(element.content), ", ", [](std::string* out, const XmlElement& e){ out->append(e.ToString()); }), "]"); + } + + absl::Format(&sink, "XmlElement{tag_name=%s, attributes={%s}, content=%s}", + element.tag_name, attrs_str_repr, content_repr); + } +}; + +} // namespace fuzztest::internal +``` + +### Helper Domains + +Several helper domains are defined to generate the constituent parts of an XML element: + +- `XmlTagName()`: Generates valid XML tag names (alphanumeric, starting with a letter). +- `XmlAttributeName()`: Generates valid XML attribute names (similar rules to tag names). +- `XmlAttributeValue()`: Generates string attribute values using printable ASCII characters (excluding quotes, which are handled by the serialization). +- `XmlAttributes()`: Creates a map of attribute name-value pairs. +- `XmlTextContent()`: Produces simple text strings that can serve as the content of an XML element. + +### `XmlElementDomain` Implementation + +The main domain, `XmlElementDomain()`, orchestrates the generation of `XmlElement` objects and their subsequent serialization into XML strings. + +- **`fuzztest::DomainBuilder<XmlElement>`**: This is used to define the recursive structure of `XmlElement`. It allows an `XmlElement` to contain other `XmlElement` objects as children. +- **Content Generation**: The content of an element (`XmlContentType`) is generated using `fuzztest::OneOf`. This domain chooses between: + - Simple text content, produced by `XmlTextContent().Map(...)`. + - A vector of child `XmlElement` objects, produced by `builder.RecursiveContainerOf<std::vector<XmlElement>>(...).Map(...)`. The `RecursiveContainerOf` is crucial for creating nested XML structures, with `max_depth` and `max_elements` parameters to control complexity. +- **Object Construction**: `builder.Set(...)` is used to specify how to construct an `XmlElement` object, providing the domains for its `tag_name`, `attributes`, and `content` members. +- **Serialization to String**: Finally, `builder.Build().Map([](XmlElement&& element) { return element.ToString(); })` takes the generated `XmlElement` object and calls its `ToString()` method to produce the final XML string. + +```cpp +// Located in: fuzztest/internal/domains/xml_domain.h + +// Domain for XML tag names (alphanumeric, starting with a letter) +inline auto XmlTagName() { + return StringOf(AlphaNumericChar()).WithMinSize(1).Filter([](const std::string& s) { + return !s.empty() && std::isalpha(s[0]); + }); +} + +// Domain for XML attribute names (alphanumeric, starting with a letter) +inline auto XmlAttributeName() { + return StringOf(AlphaNumericChar()).WithMinSize(1).Filter([](const std::string& s) { + return !s.empty() && std::isalpha(s[0]); + }); +} + +// Domain for XML attribute values (printable ASCII characters, excluding quotes) +inline auto XmlAttributeValue() { + return StringOf(CharacterSet(" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'()*+,-./:;<=>?@[]^_`{|}~")); +} + +// Domain for XML attributes (a map of name-value pairs) +inline auto XmlAttributes() { + return Map( + [](auto&&... args) { + return std::map<std::string, std::string>(std::forward<decltype(args)>(args)...); + }, + VectorOf(PairOf(XmlAttributeName(), XmlAttributeValue())).WithMaxSize(5)); +} + +// Domain for XML content (text) +inline auto XmlTextContent() { + return StringOf(PrintableAsciiChar()); +} + +// Main XML Element Domain +inline auto XmlElementDomain() { + DomainBuilder<XmlElement> builder; + + // Define the domain for the content of an XML element. + // It can be either a simple text string or a vector of child XmlElement objects. + // MaxDepth is used for the recursive part to prevent infinite recursion. + // MaxElements for the container size. + auto xml_content_variant_domain = OneOf( + XmlTextContent().Map([](std::string s) { return XmlContentType(std::move(s)); }), + builder.RecursiveContainerOf<std::vector>(/*max_depth=*/3, /*max_elements=*/5) + .Map([](std::vector<XmlElement> v) { return XmlContentType(std::move(v)); }) + ); + + builder.Set( + XmlTagName(), // domain for tag_name + XmlAttributes(), // domain for attributes + xml_content_variant_domain // domain for content (XmlContentType) + ); + + return builder.Build().Map([](XmlElement&& element) { + // Use the ToString() method of XmlElement for serialization. + return element.ToString(); + }); +} +``` + +## Usage + +To use the XML domain in your fuzz test: + +1. **Include Header**: Add the necessary header file. + ```cpp + #include "fuzztest/internal/domains/xml_domain.h" + ``` + *(Note: The exact path might vary based on your project's include structure.)* + +2. **Use in `FUZZ_TEST`**: Specify `fuzztest::internal::XmlElementDomain()` in the `.WithDomains()` clause of your `FUZZ_TEST` macro. + +### Example Fuzz Test + +Here's an example demonstrating how to use the `XmlElementDomain` to test a hypothetical XML processing function: + +```cpp +// Located in: examples/xml_fuzz_test.cc + +// NOTE: This example uses cc_test in its BUILD file instead of cc_fuzz_test +// due to difficulties in locating the correct Bazel macro for cc_fuzz_test +// in the testing environment. When integrating FuzzTest into your own project, +// ensure your Bazel setup is correct to use cc_fuzz_test for full fuzzing +// capabilities (corpus generation, coverage guidance, etc.). +// The FUZZ_TEST macro itself is still used here and should work with a +// FuzzTest-compatible main function (like fuzztest_gtest_main). + +#include "fuzztest/fuzztest.h" +#include "fuzztest/internal/domains/xml_domain.h" // Adjust path as necessary +#include <string> +#include <iostream> +#include <stack> +#include <regex> + +// A simple placeholder function to "consume" XML strings. +void ProcessXml(const std::string& xml_string) { + // std::cout << "Generated XML: " << xml_string << std::endl; + std::regex tag_regex("<([a-zA-Z0-9_:]+)([^>]*)>"); + std::smatch match; + std::string::const_iterator search_start(xml_string.cbegin()); + std::stack<std::string> open_tags; + + while (std::regex_search(search_start, xml_string.cend(), match, tag_regex)) { + std::string tag_name = match[1].str(); + std::string full_tag = match[0].str(); + + if (full_tag.size() > 1 && full_tag[full_tag.size() - 2] == '/') { + // Self-closing tag + } else if (full_tag.size() > 0 && full_tag[1] == '/') { + // Closing tag + std::string actual_tag_name = tag_name.substr(1); + if (open_tags.empty() || open_tags.top() != actual_tag_name) { + return; + } + if (!open_tags.empty()) { + open_tags.pop(); + } + } else { + // Opening tag + open_tags.push(tag_name); + } + search_start = match.suffix().first; + } + // Optional: Assert that all tags were closed if strict well-formedness is always expected. + // FUZZTEST_ASSERT(open_tags.empty()); +} + +// Fuzz test for the ProcessXml function using the XML domain +FUZZ_TEST(XmlFuzzTest, ProcessXmlConsumesValidXml) + .WithDomains(fuzztest::internal::XmlElementDomain()); + +// Basic test with a fixed string +TEST(XmlFuzzTest, ProcessXmlSimpleValidCase) { + ProcessXml("<root><item>Test</item></root>"); +} +``` + +### Note on Bazel Configuration for the Example + +The provided example (`examples/xml_fuzz_test.cc`) is configured in its `examples/BUILD` file to run using a standard `cc_test` Bazel rule, linking with `//fuzztest:fuzztest_gtest_main`. This was a workaround due to difficulties encountered in the development environment with loading the `cc_fuzz_test` Bazel macro. + +For full-fledged fuzzing (including corpus generation, advanced coverage guidance, etc.), you should use the `cc_fuzz_test` rule provided by FuzzTest. This typically involves loading it from a `.bzl` file (e.g., `load("@com_google_fuzztest//fuzztest:build_defs.bzl", "cc_fuzz_test")`) and using `cc_fuzz_test` instead of `cc_test` in your BUILD file. Ensure your project's Bazel WORKSPACE and FuzzTest integration are set up correctly to make `cc_fuzz_test` available. + +```bazel +# Example BUILD file structure (conceptual) for cc_fuzz_test: +# load("@com_google_fuzztest//fuzztest:build_defs.bzl", "cc_fuzz_test") # Or the correct path for your setup + +# cc_fuzz_test( +# name = "xml_fuzz_test", +# srcs = ["xml_fuzz_test.cc"], +# deps = [ +# "//fuzztest:fuzztest", +# "//fuzztest/internal/domains:xml_domain_impl", # Or your path to xml_domain.h +# # Other necessary dependencies +# ], +# ) +``` + +By leveraging the XML domain, developers can create more robust and secure XML processing applications.
diff --git a/examples/BUILD b/examples/BUILD new file mode 100644 index 0000000..ea03146 --- /dev/null +++ b/examples/BUILD
@@ -0,0 +1,22 @@ +# Fuzz test example for the XML domain. + +# NOTE: This BUILD file uses cc_test instead of cc_fuzz_test due to difficulties +# in locating the correct Bazel macro for cc_fuzz_test in this environment. +# For full fuzzing capabilities, ensure your FuzzTest Bazel setup is correct +# and cc_fuzz_test is properly loaded and used. +# See comments in xml_fuzz_test.cc for more details. + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +cc_test( + name = "xml_fuzz_test", + srcs = ["xml_fuzz_test.cc"], + deps = [ + "//fuzztest:fuzztest", # Main FuzzTest library (provides FUZZ_TEST macro definitions) + "//fuzztest:fuzztest_gtest_main", # Provides a main function that runs Google Tests and Fuzz Tests + "//fuzztest/internal/domains:xml_domain_impl", # Our new XML domain library + "@com_google_googletest//:gtest", # GoogleTest library itself + ], +)
diff --git a/examples/xml_fuzz_test.cc b/examples/xml_fuzz_test.cc new file mode 100644 index 0000000..80280a3 --- /dev/null +++ b/examples/xml_fuzz_test.cc
@@ -0,0 +1,115 @@ +// NOTE: This example uses cc_test in its BUILD file instead of cc_fuzz_test +// due to difficulties in locating the correct Bazel macro for cc_fuzz_test +// in the testing environment. When integrating FuzzTest into your own project, +// ensure your Bazel setup is correct to use cc_fuzz_test for full fuzzing +// capabilities (corpus generation, coverage guidance, etc.). +// The FUZZ_TEST macro itself is still used here and should work with a +// FuzzTest-compatible main function (like fuzztest_gtest_main). + +#include "fuzztest/fuzztest.h" +#include "fuzztest/internal/domains/xml_domain.h" // Adjust path as necessary +#include <string> +#include <iostream> +#include <stack> +#include <regex> + +// A simple placeholder function to "consume" XML strings. +// For a real test, this would be a proper XML parser or processing function. +// This example will just print the generated XML and perform a trivial check. +void ProcessXml(const std::string& xml_string) { + // std::cout << "Generated XML: " << xml_string << std::endl; + + // Trivial check: Ensure all opening tags have corresponding closing tags. + // This is a very simplified check and not a full XML validation. + std::regex tag_regex("<([a-zA-Z0-9_:]+)([^>]*)>"); + std::smatch match; + std::string::const_iterator search_start(xml_string.cbegin()); + std::stack<std::string> open_tags; + + while (std::regex_search(search_start, xml_string.cend(), match, tag_regex)) { + std::string tag_name = match[1].str(); + std::string full_tag = match[0].str(); + + if (full_tag.size() > 1 && full_tag[full_tag.size() - 2] == '/') { + // Self-closing tag, ignore for stack balancing. + } else if (full_tag.size() > 0 && full_tag[1] == '/') { + // Closing tag + std::string actual_tag_name = tag_name.substr(1); // Remove '/' + if (open_tags.empty() || open_tags.top() != actual_tag_name) { + // Mismatched closing tag or closing tag without opening. + // For this simple test, we might not fail here, + // as the generator should ideally produce valid structures. + // However, real-world fuzzing would catch this with a proper parser. + // For now, we'll just note it. + // std::cerr << "Mismatched closing tag: " << actual_tag_name << std::endl; + // FUZZTEST_FAIL("Mismatched closing tag"); // Could enable this for stricter test + return; // Stop processing on error + } + if (!open_tags.empty()) { + open_tags.pop(); + } + } else { + // Opening tag + open_tags.push(tag_name); + } + search_start = match.suffix().first; + } + + // FUZZTEST_ASSERT(open_tags.empty()); // Assert all tags were closed + // If open_tags is not empty, it means some tags were not closed. + // Depending on how strict we want to be with the generator: + if (!open_tags.empty()) { + // std::cerr << "Not all tags were closed. Open tags: " << open_tags.size() << std::endl; + // FUZZTEST_FAIL("Not all tags were closed."); + } +} + +// Fuzz test for the ProcessXml function using the XML domain +FUZZ_TEST(XmlFuzzTest, ProcessXmlConsumesValidXml) + .WithDomains(fuzztest::internal::XmlElementDomain()); + +// Basic test with a fixed string to ensure ProcessXml works as expected for a simple case. +// This is more of a unit test for ProcessXml itself. +TEST(XmlFuzzTest, ProcessXmlSimpleValidCase) { + ProcessXml("<root><item>Test</item></root>"); +} + +TEST(XmlFuzzTest, ProcessXmlSimpleSelfClosing) { + ProcessXml("<root><item name=\"test\"/></root>"); +} + +TEST(XmlFuzzTest, ProcessXmlSimpleMismatch) { + // This test is expected to "pass" as ProcessXml currently doesn't hard fail. + ProcessXml("<root><item>Test</mismatch></root>"); +} + +// To run this test, you would typically need to link against the FuzzTest library +// and have a BUILD file entry. For example (using Bazel): +// +// cc_fuzz_test( +// name = "xml_fuzz_test", +// srcs = ["xml_fuzz_test.cc"], +// corpus = [], // Add seed corpus if any +// deps = [ +// "//fuzztest", +// "//fuzztest/internal/domains:xml_domain_h_library", // Assuming xml_domain.h is part of a library +// ], +// ) + +// For CMake, you would add an executable and link fuzztest::fuzztest_main and other necessary targets. + +int main(int argc, char** argv) { + // Initialize FuzzTest + // This is usually handled by cc_fuzz_test in Bazel, + // but if running as a standalone gtest, you might need it. + // testing::InitGoogleTest(&argc, argv); // If mixing with GTest tests. + // return RUN_ALL_TESTS(); + // For a pure FuzzTest setup, FuzzTest automatically registers and runs tests. + // If FUZZ_TEST is defined, it implies FuzzTest's main. + // If only TEST is defined, you need Google Test's main. + // The FuzzTest library provides a main function when `FUZZ_TEST` macros are used. + // So, a custom main is often not needed unless for specific GTest setups. + // For Bazel's cc_fuzz_test, no main() is needed here. + // For other build systems, you might need to link with FuzzTest's main library. + return 0; // Placeholder main, actual execution is handled by FuzzTest framework. +}
diff --git a/fuzztest/internal/domains/BUILD b/fuzztest/internal/domains/BUILD index 5a1d738..29d0ec5 100644 --- a/fuzztest/internal/domains/BUILD +++ b/fuzztest/internal/domains/BUILD
@@ -214,3 +214,15 @@ hdrs = ["utf.h"], deps = ["@abseil-cpp//absl/strings:string_view"], ) + +cc_library( + name = "xml_domain_impl", + hdrs = ["xml_domain.h"], + deps = [ + ":core_domains_impl", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:variant", # For std::variant + "@com_google_fuzztest//fuzztest/internal:meta", + # Add other necessary Abseil or FuzzTest internal dependencies if xml_domain.h evolves + ], +)
diff --git a/fuzztest/internal/domains/xml_domain.h b/fuzztest/internal/domains/xml_domain.h new file mode 100644 index 0000000..4f96512 --- /dev/null +++ b/fuzztest/internal/domains/xml_domain.h
@@ -0,0 +1,152 @@ +#ifndef FUZZTEST_INTERNAL_DOMAINS_XML_DOMAIN_H_ +#define FUZZTEST_INTERNAL_DOMAINS_XML_DOMAIN_H_ + +#include <string> +#include <vector> + +#include "fuzztest/internal/domains/domain_base.h" +#include "fuzztest/internal/domains/string_domains.h" // For StringOf, CharacterSet +#include "fuzztest/internal/domains/container_of_impl.h" // For VectorOf +#include "fuzztest/internal/domains/map_impl.h" // For Map +#include "fuzztest/internal/domains/one_of_impl.h" // For OneOf +#include "fuzztest/internal/domains/domain_builder.h" // For DomainBuilder +#include "fuzztest/internal/meta.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" + + +namespace fuzztest::internal { + +// Forward declaration for recursive definition +class XmlElement; + +// Domain for XML tag names (alphanumeric, starting with a letter) +inline auto XmlTagName() { + return StringOf(AlphaNumericChar()).WithMinSize(1).Filter([](const std::string& s) { + return !s.empty() && std::isalpha(s[0]); + }); +} + +// Domain for XML attribute names (alphanumeric, starting with a letter) +inline auto XmlAttributeName() { + return StringOf(AlphaNumericChar()).WithMinSize(1).Filter([](const std::string& s) { + return !s.empty() && std::isalpha(s[0]); + }); +} + +// Domain for XML attribute values (printable ASCII characters, excluding quotes) +inline auto XmlAttributeValue() { + return StringOf(CharacterSet(" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'()*+,-./:;<=>?@[]^_`{|}~")); +} + +// Domain for XML attributes (a map of name-value pairs) +inline auto XmlAttributes() { + return Map( + [](auto&&... args) { + return std::map<std::string, std::string>(std::forward<decltype(args)>(args)...); + }, + VectorOf(PairOf(XmlAttributeName(), XmlAttributeValue())).WithMaxSize(5)); +} + + +// Domain for XML content (text or nested elements) +// This will be part of the recursive definition using DomainBuilder +// For now, a simple text content domain. +inline auto XmlTextContent() { + return StringOf(PrintableAsciiChar()); +} + + +// Main XML Element Domain +inline auto XmlElementDomain() { + DomainBuilder<XmlElement> builder; + + // Define the domain for the content of an XML element. + // It can be either a simple text string or a vector of child XmlElement objects. + // MaxDepth is used for the recursive part to prevent infinite recursion. + // MaxElements for the container size. + auto xml_content_variant_domain = OneOf( + XmlTextContent().Map([](std::string s) { return XmlContentType(std::move(s)); }), + builder.RecursiveContainerOf<std::vector>(/*max_depth=*/3, /*max_elements=*/5) + .Map([](std::vector<XmlElement> v) { return XmlContentType(std::move(v)); }) + ); + + builder.Set( + XmlTagName(), // domain for tag_name + XmlAttributes(), // domain for attributes + xml_content_variant_domain // domain for content (XmlContentType) + ); + // The DomainBuilder by default uses fuzztest::Arbitrary<XmlElement> which requires + // the type to be default constructible and aggregate initializable. + // Since we have a custom constructor and want to use specific domains for fields, + // we provide a factory function. + // builder.Set relies on the order of arguments matching the constructor of XmlElement, + // or matching the order of fields if it were an aggregate. + + return builder.Build().Map([](XmlElement&& element) { + // Use the ToString() method of XmlElement for serialization. + return element.ToString(); + }); +} + +#include <variant> // Required for std::variant + +// Forward declaration +class XmlElement; + +// Define content type: can be a string (text) or a vector of child XmlElements +using XmlContentType = std::variant<std::string, std::vector<XmlElement>>; + +// Represents an XML element. +class XmlElement { + public: + std::string tag_name; + std::map<std::string, std::string> attributes; + XmlContentType content; + + XmlElement() = default; + XmlElement(std::string tag, std::map<std::string, std::string> attrs, XmlContentType cont) + : tag_name(std::move(tag)), attributes(std::move(attrs)), content(std::move(cont)) {} + + // Function to serialize the XmlElement to a string + std::string ToString() const { + std::string attrs_str; + for (const auto& attr : attributes) { + attrs_str += absl::StrCat(" ", attr.first, "=\"", attr.second, "\""); + } + + std::string content_str; + if (std::holds_alternative<std::string>(content)) { + content_str = std::get<std::string>(content); + } else if (std::holds_alternative<std::vector<XmlElement>>(content)) { + for (const auto& child : std::get<std::vector<XmlElement>>(content)) { + content_str += child.ToString(); + } + } + return absl::StrCat("<", tag_name, attrs_str, ">", content_str, "</", tag_name, ">"); + } + + template <typename Sink> + friend void AbslStringify(Sink& sink, const XmlElement& element) { + std::string attrs_str_repr; + for (const auto& attr : element.attributes) { + if (!attrs_str_repr.empty()) attrs_str_repr += ", "; + attrs_str_repr += absl::StrCat(attr.first, "=", attr.second); + } + + std::string content_repr; + if (std::holds_alternative<std::string>(element.content)) { + content_repr = absl::StrCat("\"", std::get<std::string>(element.content), "\""); + } else if (std::holds_alternative<std::vector<XmlElement>>(element.content)) { + content_repr = absl::StrCat("[", absl::StrJoin(std::get<std::vector<XmlElement>>(element.content), ", ", [](std::string* out, const XmlElement& e){ out->append(e.ToString()); }), "]"); + } + + absl::Format(&sink, "XmlElement{tag_name=%s, attributes={%s}, content=%s}", + element.tag_name, attrs_str_repr, content_repr); + } +}; + + +} // namespace fuzztest::internal + +#endif // FUZZTEST_INTERNAL_DOMAINS_XML_DOMAIN_H_
diff --git a/xpath_validator/src/xpath_validator/domain/xml_domain.py b/xpath_validator/src/xpath_validator/domain/xml_domain.py new file mode 100644 index 0000000..8621c7f --- /dev/null +++ b/xpath_validator/src/xpath_validator/domain/xml_domain.py
@@ -0,0 +1,45 @@ +import hypothesis.strategies as st + +# Helper function for generating valid XML tag names +def tag_names(): + return st.text(alphabet=st.characters(min_codepoint=ord('a'), max_codepoint=ord('z')), min_size=1) + +# Helper function for generating valid XML attribute names +def attribute_names(): + return st.text(alphabet=st.characters(min_codepoint=ord('a'), max_codepoint=ord('z')), min_size=1) + +# Helper function for generating valid XML attribute values +def attribute_values(): + return st.text(alphabet=st.characters(min_codepoint=ord('a'), max_codepoint=ord('z'), whitelist_categories=('N', 'L', 'P', 'Z', 'S')), min_size=1) + +# Helper function for generating XML attributes +def attributes(): + return st.dictionaries(attribute_names(), attribute_values()) + +# Helper function for generating XML content (text) +def content(): + return st.text(alphabet=st.characters(min_codepoint=ord('a'), max_codepoint=ord('z'), whitelist_categories=('N', 'L', 'P', 'Z', 'S'))) + +# Helper function to format attributes into a string +def format_attributes(attrs): + if not attrs: + return "" + return " " + " ".join(f'{k}="{v}"' for k, v in attrs.items()) + +# Define the XML domain using RecursiveDomain +xml_domain = st.recursive( + st.builds(lambda tag, attrs_str, children_content: f"<{tag}{attrs_str}>{children_content}</{tag}>", + tag_names(), + attributes().map(format_attributes), + st.deferred(lambda: st.lists(xml_domain | content())).map("".join)), + lambda children: st.builds(lambda tag, attrs_str, children_content: f"<{tag}{attrs_str}>{children_content}</{tag}>", + tag_names(), + attributes().map(format_attributes), + children.map("".join)) +) + +if __name__ == '__main__': + # Example usage: + # Generate a sample XML string + sample_xml = xml_domain.example() + print(sample_xml)