{"id":34696609,"url":"https://github.com/pholser/junit-theories","last_synced_at":"2026-05-27T05:37:39.876Z","repository":{"id":9072411,"uuid":"10844205","full_name":"pholser/junit-theories","owner":"pholser","description":"JUnit theories runner -- supports generics in theory parms","archived":false,"fork":false,"pushed_at":"2015-06-12T19:37:19.000Z","size":388,"stargazers_count":1,"open_issues_count":2,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-26T10:47:05.785Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pholser.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-06-21T14:26:59.000Z","updated_at":"2017-07-30T16:29:11.000Z","dependencies_parsed_at":"2022-09-04T19:32:17.632Z","dependency_job_id":null,"html_url":"https://github.com/pholser/junit-theories","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/pholser/junit-theories","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pholser%2Fjunit-theories","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pholser%2Fjunit-theories/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pholser%2Fjunit-theories/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pholser%2Fjunit-theories/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pholser","download_url":"https://codeload.github.com/pholser/junit-theories/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pholser%2Fjunit-theories/sbom","scorecard":{"id":732150,"data":{"date":"2025-08-11","repo":{"name":"github.com/pholser/junit-theories","commit":"38821e82beae6bc8d26ff9e8a5c3e08098915791"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-269g-pwp5-87pp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T14:43:51.283Z","repository_id":9072411,"created_at":"2025-08-22T14:43:51.284Z","updated_at":"2025-08-22T14:43:51.284Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33553127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-24T22:35:37.736Z","updated_at":"2026-05-27T05:37:39.868Z","avatar_url":"https://github.com/pholser.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"JUnit Theories Runner\n----\n\nThis is a port of the JUnit theories runner into junit.contrib.\n\nAs of version 5.0, junit-theories is built with JDK 8, and source/target-compatible\nwith 1.8 and beyond.\n\nIn addition to being current with the theories implementation in JUnit 4.12 and\ndepending on its core, this implementation contains a resolution for\n[JUnit GitHub issue 64](http://github.com/junit-team/junit/issues/64), making it possible for\n[junit-quickcheck](http://github.com/pholser/junit-quickcheck) to generate values for theory\nparameters involving generics in a safe manner.\n\nUltimately it is hoped that this rendition becomes the sanctioned theories runner for JUnit,\nso that the one in the core can be removed, meaning that this runner can evolve without new\nreleases of JUnit.\n\n**PLEASE NOTE**: The classes that comprise this rendition of the JUnit theories runner are packaged\nas `org.junit.contrib.theories.*`, rather than `org.junit.experimental.theories.*`. Be mindful of\nwhich one you're using.\n\n## Downloading\n\nReleases are synced to the central Maven repository. Declare a dependency element in your POM like so:\n\n    ...\n    \u003cdependencies\u003e\n      ...\n      \u003cdependency\u003e\n        \u003cgroupId\u003eorg.junit.contrib\u003c/groupId\u003e\n        \u003cartifactId\u003ejunit-theories\u003c/artifactId\u003e\n        \u003cversion\u003e5.0-alpha-1\u003c/version\u003e\n      \u003c/dependency\u003e\n      ...\n    \u003c/dependencies\u003e\n    ...\n\n### What is a theory?\n\nMost JUnit tests are example-based: given a specific set of inputs, the test subject behaves in a\nparticular way or responds with a specific answer. For example, here are some tests we might write\nwhen test-driving a prime factors kata:\n\n    public class PrimeFactors {\n        public static List\u003cInteger\u003e of(int n) {\n            // ...\n        }\n    }\n\n    public class UnparameterizedPrimeFactorsTest {\n        @Test public void one() {\n            assertEquals(Collections.emptyList(), PrimeFactors.of(1));\n        }\n\n        @Test public void two() {\n            assertEquals(Arrays.asList(2), PrimeFactors.of(2));\n        }\n\n        @Test public void three() {\n            assertEquals(Arrays.asList(3), PrimeFactors.of(3));\n        }\n\n        @Test public void four() {\n            assertEquals(Arrays.asList(2, 2), PrimeFactors.of(4));\n        }\n\n        @Test public void five() {\n            assertEquals(Arrays.asList(5), PrimeFactors.of(5));\n        }\n\n        // etc...\n    }\n\nWe can eliminate duplicated test logic sometimes by using parameterized tests:\n\n    @RunWith(Parameterized.class)\n    public class PrimeFactorsTest {\n        private final int target;\n        private final List\u003cInteger\u003e expectedFactors;\n\n        public PrimeFactorsTest(int target, List\u003cInteger\u003e expectedFactors) {\n            this.target = target;\n            this.expectedFactors = expectedFactors;\n        }\n\n        @Parameters public static Collection\u003c?\u003e data() {\n            return asList(new Object[][] {\n                { 1, Collections.emptyList() },\n                { 2, Arrays.asList(2) },\n                { 3, Arrays.asList(3) },\n                { 4, Arrays.asList(2, 2) },\n                { 5, Arrays.asList(5) },\n                // etc...\n            });\n        }\n\n        @Test public void comparison() {\n            assertEquals(Integer.toString(target), expectedFactors, PrimeFactors.of(target));\n        }\n    }\n\nNeither of these tests expresses important characteristics we want the the answers given by\n`PrimeFactors.of()` to exhibit: No matter what positive integer you give the method...\n\n* The factors must be prime\n* The factors must multiply together to give the original integer\n* Factorizations of two distinct integers must themselves be distinct (the Fundamental Theorem of Arithmetic)\n\nWhenever we want to express characteristics of a test subject that hold for entire classes of\ninputs, and we can express the characteristics in terms of inputs and outputs, we can codify these\ndesired characteristics in _theories_. Here are the characteristics of `PrimeFactors.of()`\nexpressed as theories:\n\n    @RunWith(Theories.class)\n    public class PrimeFactorsTheories {\n        @DataPoint public static final int ONE = 1;\n        @DataPoint public static final int TWO = 2;\n        @DataPoint public static final int THREE = 3;\n        @DataPoints public static int[] moreExamples = { 4, 5, 6 };\n\n        @DataPoint public static int anotherExample() {\n            return 5;\n        }\n\n        @DataPoints public static int[] stillMoreExamples() {\n            return new int[] { 6, 7, 8, 9 };\n        }\n\n        @Theory public void factorsPassPrimalityTest(int n) {\n            assumeThat(n, greaterThan(0));\n\n            for (int each : PrimeFactors.of(n))\n                assertTrue(BigInteger.valueOf(each).isProbablePrime(1000));\n        }\n\n        @Theory public void factorsMultiplyToOriginal(int n) {\n            assumeThat(n, greaterThan(0));\n\n            int product = 1;\n            for (int each : PrimeFactors.of(n))\n                product *= each;\n\n            assertEquals(n, product);\n        }\n\n        @Theory public void factorizationsAreUnique(int m, int n) {\n            assumeThat(m, greaterThan(0));\n            assumeThat(n, greaterThan(0));\n            assumeThat(m, not(equalTo(n)));\n\n            assertThat(PrimeFactors.of(m), not(equalTo(PrimeFactors.of(n))));\n        }\n    }\n\n### How to formulate theories\n\n* A test class containing theories is run with the `Theories` runner.\n\n* A method that represents a theory is annotated with `@Theory` instead of the usual `@Test`.\n\n* A theory method accepts parameters, which represent arbitrary inputs to the theory.\n\n* Theory methods can state _assumptions_ about their inputs using the methods of `Assume`.\nFor example, the theories above assume that we're dealing with positive integers. The remainder\nof a theory is not run if one of its assumptions is violated.\n\n* Theory methods state success criteria in the form of _assertions_, just like regular JUnit tests\ndo.\n\n* By default, inputs are supplied to theories from fields and methods on the class annotated as\neither `@DataPoint` or `@DataPoints`. A theory method is invoked once for every combination of data\npoints that match on type.\n\n#### Alternate means of providing theory data\n\nThe data points method is somewhat flawed, because we are still baking concrete example data into\nthe theory class. It would be nice to be able to decouple the theory from data that is used to\nverify the theory -- after all, a theory should hold for potentially infinite classes of data.\n\nThankfully, we can use `ParameterSupplier`s for just this purpose:\n\n    public class PositiveIntegerParameterSupplier extends ParameterSupplier {\n        private final Random random = new SecureRandom();\n\n        @Override\n        public List\u003cPotentialAssignment\u003e getValueSources(ParameterSignature sig) {\n            List\u003cPotentialAssignment\u003e values = new ArrayList\u003cPotentialAssignment\u003e();\n\n            for (int i = 0; i \u003c 100; ++i) {\n                int next = random.nextInt(Integer.MAX_VALUE);\n                if (next == 0)\n                    next = Integer.MAX_VALUE;\n                values.add(PotentialAssignment.forValue(Integer.toString(next), next));\n            }\n\n            return values;\n        }\n    }\n\n    @Target(PARAMETER)\n    @Retention(RUNTIME)\n    @ParametersSuppliedBy(PositiveIntegerParameterSupplier.class)\n    public @interface AnyPositive {\n    }\n\n    @RunWith(Theories.class)\n    public class PrimeFactorsTheories {\n        @Theory public void factorsPassPrimalityTest(@AnyPositive int n) {\n            for (int each : PrimeFactors.of(n))\n                assertTrue(BigInteger.valueOf(each).isProbablePrime(1000));\n        }\n\n        @Theory public void factorsMultiplyToOriginal(@AnyPositive int n) {\n            int product = 1;\n            for (int each : PrimeFactors.of(n))\n                product *= each;\n\n            assertEquals(n, product);\n        }\n\n        @Theory public void factorizationsAreUnique(@AnyPositive int m, @AnyPositive int n) {\n            assumeThat(m, not(equalTo(n)));\n\n            assertThat(PrimeFactors.of(m), not(equalTo(PrimeFactors.of(n))));\n        }\n    }\n\nTo customize how data are fed to a given theory parameter:\n\n* Create a class that extends `ParameterSupplier`\n\n* Create an annotation that is itself annotated with\n`@ParametersSuppliedBy(YourParameterSupplier.class)`\n\n* Mark the desired theory parameter with your annotation\n\nIn the example above, we create a `PositiveIntegerParameterSupplier` that gives 100 positive\nintegers at random when invoked. Then, we create an annotation `@AnyPositive` and apply it to the\ntheory parameters. This allows us to get rid of our baked-in data points and test the theory\nagainst lots of random values. Also, because our parameter supplier is coded to supply only\npositive integers, we can remove the positivity assumptions from the theories.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpholser%2Fjunit-theories","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpholser%2Fjunit-theories","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpholser%2Fjunit-theories/lists"}