{"id":39584752,"url":"https://github.com/SimpleFinance/simplespec","last_synced_at":"2026-01-26T15:01:19.921Z","repository":{"id":988238,"uuid":"793813","full_name":"SimpleFinance/simplespec","owner":"SimpleFinance","description":"A small Scala library for writing specs as simple classes and methods (no longer maintained).","archived":true,"fork":false,"pushed_at":"2017-07-18T14:17:08.000Z","size":199,"stargazers_count":38,"open_issues_count":3,"forks_count":21,"subscribers_count":21,"default_branch":"master","last_synced_at":"2026-01-11T18:44:53.120Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SimpleFinance.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2010-07-23T18:41:07.000Z","updated_at":"2023-01-28T19:39:47.000Z","dependencies_parsed_at":"2022-08-16T11:45:14.612Z","dependency_job_id":null,"html_url":"https://github.com/SimpleFinance/simplespec","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/SimpleFinance/simplespec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimpleFinance%2Fsimplespec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimpleFinance%2Fsimplespec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimpleFinance%2Fsimplespec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimpleFinance%2Fsimplespec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SimpleFinance","download_url":"https://codeload.github.com/SimpleFinance/simplespec/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimpleFinance%2Fsimplespec/sbom","scorecard":{"id":130290,"data":{"date":"2025-08-11","repo":{"name":"github.com/SimpleFinance/simplespec","commit":"02657838f9c9b5103c207383a08eaa36df16bce4"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"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":"Code-Review","score":2,"reason":"Found 4/17 approved changesets -- score normalized to 2","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":"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":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"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":"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"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"}},{"name":"SAST","score":-1,"reason":"internal error: internal error: Client.Checks.ListCheckRunsForRef: error during graphqlHandler.setupCheckRuns: non-200 OK status code: 502 Bad Gateway body: \"\u003chtml\u003e\\r\\n\u003chead\u003e\u003ctitle\u003e502 Bad Gateway\u003c/title\u003e\u003c/head\u003e\\r\\n\u003cbody\u003e\\r\\n\u003ccenter\u003e\u003ch1\u003e502 Bad Gateway\u003c/h1\u003e\u003c/center\u003e\\r\\n\u003chr\u003e\u003ccenter\u003enginx\u003c/center\u003e\\r\\n\u003c/body\u003e\\r\\n\u003c/html\u003e\\r\\n\"","details":null,"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T05:07:43.736Z","repository_id":988238,"created_at":"2025-08-16T05:07:43.736Z","updated_at":"2025-08-16T05:07:43.736Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28781308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T13:55:28.044Z","status":"ssl_error","status_checked_at":"2026-01-26T13:55:26.068Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":"2026-01-18T07:35:27.100Z","updated_at":"2026-01-26T15:01:19.915Z","avatar_url":"https://github.com/SimpleFinance.png","language":"Scala","readme":"simplespec\n==========\n\n(**NOTE**: This project is **no longer actively maintained**. For an\nactively developed replacement, we recommend [ScalaTest]\n(http://www.scalatest.org). If you have any interest in taking over\nmaintenance and development, please [file an issue]\n(https://github.com/SimpleFinance/simplespec/issues/new).)\n\n*No seriously, keep it simple.*\n\n**simplespec** is a thin Scala wrapper over\n[JUnit](http://www.junit.org/), the most commonly-used test framework on\nthe JVM. simplespec was originally written by Coda Hale and was\nsubsequently maintained and developed by Simple until June 2016. The\nlibrary features extensible Hamcrest matchers, easy mocks, and other\nniceties.\n\n\u003cimg src=\"https://travis-ci.org/SimpleFinance/simplespec.png\" /\u003e\n\n\nRequirements\n------------\n\n* Scala 2.12.1\n* JUnit 4.11\n* Mockito 1.9.5\n\n(Scala 2.11.0 \u0026 2.10.2, 2.9.1, and 2.9.2 are supported in simplespec 0.8.4, 0.6.0, and 0.7.0, respectively.)\n\n\nGetting Started\n---------------\n\n**First**, specify simplespec as a dependency.\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.simple\u003c/groupId\u003e\n        \u003cartifactId\u003esimplespec_2.12\u003c/artifactId\u003e\n        \u003cversion\u003e0.9.0\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nIf you are on Scala 2.11.0, you should use:\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.simple\u003c/groupId\u003e\n        \u003cartifactId\u003esimplespec_2.11\u003c/artifactId\u003e\n        \u003cversion\u003e0.8.4\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nIf you are on Scala 2.10.2, you should use:\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.simple\u003c/groupId\u003e\n        \u003cartifactId\u003esimplespec_2.10.2\u003c/artifactId\u003e\n        \u003cversion\u003e0.8.4\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nIf you are on Scala 2.9.2, you should use:\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.simple\u003c/groupId\u003e\n        \u003cartifactId\u003esimplespec_2.9.2\u003c/artifactId\u003e\n        \u003cversion\u003e0.7.0\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nAnd for 2.9.1:\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.simple\u003c/groupId\u003e\n        \u003cartifactId\u003esimplespec_2.9.1\u003c/artifactId\u003e\n        \u003cversion\u003e0.6.0\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n\n**Second**, write a spec:\n\n```scala\nimport com.example.Stack\nimport org.junit.Test\nimport com.simple.simplespec.Spec\n\nclass StackSpec extends Spec {\n  class `An empty stack` {\n    val stack = Stack()\n\n    @Test def `has a size of zero` = {\n      stack.size.must(be(0))\n    }\n\n    @Test def `is empty` = {\n      stack.isEmpty.must(be(true))\n    }\n\n    class `with an item added to it` {\n      stack += \"woo\"\n\n      @Test def `might have an item in it` = {\n        stack.must(be(empty))\n      }\n    }\n  }\n}\n```\n\n\nExecution Model\n---------------\n\nThe execution model for a `Spec` is just a logical extension of how JUnit itself\nworks -- a `Spec` class contains one or more regular classes, each of which can\ncontain zero or more `@Test`-annotated methods or further nested classes.\n\nWhen JUnit runs the `Spec` class, it creates new instances of each class for\neach test method run, allowing for full test isolation. In the above example,\nfirst an instance of `StackSpec` would be created, then an instance of\n`` StackSpec#`An empty stack` ``, then an instance of\n`` StackSpec#`An empty stack`#`with an item added to it` ``, and finally its\n`` `might have an item in it` `` method is run as a test.\n\nThe tradeoff of this execution model (vs. one which shares state between test\ninvocation) is that tests which create a substantial amount of shared state\n(e.g., data-intensive tests) spend a lot of time setting up or tearing down\nstate.\n\nUnlike JUnit, simplespec doesn't require your test methods to return void.\n\nThe outer `Spec` instance has `beforeEach` and `afterEach` methods which can be\noverridden to perform setup and teardown tasks for each test contained in the\ncontext. simplespec also provides `BeforeEach`, `AfterEach`, and\n`BeforeAndAfterEach` traits which inner classes can extend to perform more\ntightly-scoped setup and teardown tasks.\n\n\nMatchers\n--------\n\nsimplespec provides a thin layer over\n[Hamcrest matchers](http://code.google.com/p/hamcrest/) to allow for declarative\nassertions in your tests:\n\n```scala\nstack.must(be(empty))\n```\n\nsimplespec includes the following matchers by default, but you're encouraged to\nwrite your own:\n\n* `x.must(equal(y))`: Asserts `x == y`.\n* `x.must(be(y))`: A synonym for `equal`.\n* `x.must(beA(klass))`: Asserts that `x` is assignable as an instance of `klass`.\n* `x.must(be(matcher))`: Asserts that `matcher` applies to `x`.\n* `x.must(not(be(matcher)))`: Asserts that `matcher` does *not* apply to `x`.\n* `x.must(be(empty))`: Asserts that `x` is a `TraversableLike` which is empty.\n* `x.must(haveSize(n))`: Asserts that `x` is a `TraversableLike` which has `n`\n  elements.\n* `x.must(contain(y))`: Asserts that `x` is a `SeqLike` which contains the\n  element `y`.\n* `x.must(be(notNull))`: Asserts that `x` is not `null`.\n* `x.must(be(approximately(y, delta)))`: Asserts that `x` is within `delta` of\n  `y`. Useful for floating-point math.\n* `x.must(be(lessThan(2)))`: Asserts that `x` is less than `2`.\n* `x.must(be(greaterThan(2)))`: Asserts that `x` is greater than `2`.\n* `x.must(be(lessThanOrEqualTo(2)))`: Asserts that `x` is less than or equal to\n  `2`.\n* `x.must(be(greaterThanOrEqualTo(2)))`: Asserts that `x` is greater than or\n  equal to `2`.\n* `x.must(startWith(\"woo\"))`: Asserts that string `x` starts with `\"woo\"`.\n* `x.must(endWith(\"woo\"))`: Asserts that string `x` ends with `\"woo\"`.\n* `x.must(contain(\"woo\"))`: Asserts that string `x` contains with `\"woo\"`.\n* ``x.must(`match`(\".*oo\".r))``: Asserts that string `x` matches the regular\n  expression `.*oo`.\n\nMatchers like `be` and `not` take matchers as their arguments, which means you\ncan write domain-specific matchers for your tests:\n\n```scala\nclass IsSufficientlyCromulentMatcher extends BaseMatcher[Fromulator] {\n  def describeTo(description: Description) {\n    description.appendText(\"a cromulemnt fromulator\")\n  }\n\n  def matches(item: AnyRef) = item match {\n    case fromulator: Fromulator =\u003e fromulator.isCromulent\n    case _ =\u003e false\n  }\n}\n\ntrait CromulentMatcher {\n  def cromulent = new IsSufficientlyCromulentMatcher\n}\n\nclass BlahBlahSpec extends Spec with CromulentMatcher {\n  class `A Fromulator` {\n    val fromulator = new Fromulator\n\n    def `is cromulent` = {\n      fromulator.must(be(cromulent)\n    }\n  }\n}\n```\n\nsimplespec also includes two helper methods: `evaluating` and `eventually`.\n\n`evaluating` captures a closure and allows you to make assertions about what\nhappens when it's evaluated:\n\n```scala\n@Test def `throws an exception` = {\n  evaluating {\n    dooHicky.stop()\n  }.must(throwAn[UnsupportedOperationException])\n}\n```\n\n`eventually` also captures a closure, but allows you to assert things about\nwhat happens when the closure is evaluated which might not be true the first\nfew times:\n\n```scala\n@Test def `decay to zero` = {\n  eventually {\n    thingy.rate\n  }.must(be(approximately(0.0, 0.001)))\n}\n```\n\nSee `Matchers.scala` for the full run-down.\n\n\nMocks\n-----\n\nSimpleSpec uses [Mockito](http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html) for mocking stuff. It has its\nown wrappers around Mockito to make things a bit easier.\n\n```scala\nclass PublisherSpec extends Spec {\n  class `A publisher` {\n    val message = mock[Message]\n\n    val queue = mock[Queue]\n    queue.enqueue(any).returns(0, 1, 2, 3)\n\n    val publisher = new Publisher(queue)\n\n    @Test def `sends a message to the queue` = {\n      publisher.receive(message)\n\n      verify.one(queue).enqueue(message)\n    }\n  }\n}\n```\n\n### Mock Stubbing\n\nBy default, when you mock something and call a method on it, the call will\nreturn `null` or a basic value like `0` or `false` for primitives.\n\nIf you want to control what the mocked object returns for a given method call,\nyou can use `returns`, `throws`, or `answersWith`:\n\n```scala\nval foo = mock[FooService]\n\n// .returns() can be used when you just want to return a static value\nfoo.getNumber(\"one\").returns(1)\nfoo.getNumber(\"two\").returns(2)\n\n// .throws() will make the call throw the given exception.\n// Note: if Mockito complains about a checked exception being invalid, you'll\n// need to use .answersWith() to throw the exception instead.\nfoo.getNumber(\"dogs\").throws(new NumberFormatException)\n\n// .answersWith() will call the function you pass it and use its result\n// as the mocked return value.\nfoo.getNumber(\"three\").answersWith(_ =\u003e 3)\nfoo.getNumber(\"dogs\").answersWith(_ =\u003e throw new NumberFormatException)\n```\n\nThese stubbing functions are sensitive to order. So this:\n\n```scala\nfoo.get(1).returns(\"cats\")\nfoo.get(1).returns(\"dogs\")\n```\n\nWill return `\"dogs\"` every time you call `foo.get(1)`.\n\nYou can also dynamically match arguments in method calls. The simplest way is\nto use `any` to match any argument of a given type:\n\n```scala\nfoo.get(any[Int]).returns(None)\nfoo.get(1).returns(Some(\"dogs\"))\n```\n\nThis example uses the fact that stubs are sensitive to ordering to its\nadvantage.\n\nNote that if you match *any* of the method's arguments with a dymanic matcher\nlike `any`, you'll need to match them *all* dynamically. For example, this does\n**not** work:\n\n```scala\nfoo.get(any[Int], \"Hello\").returns(...)\n```\n\nYou can use `equalTo` to get around this:\n\n```scala\nfoo.get(any[Int], equalTo[String](\"Hello\")).returns(...)\n```\n\nAvailable dynamic matchers:\n\n* `any[A](implicit mf: Manifest[A])`: A matcher which will accept any instance.\n* `isA[A](implicit mf: Manifest[A])`: A matcher which will accept any instance of the given type.\n* `equalTo[A](value: A)`: A matcher which will accept any instance of the given type which is equal to the given value.\n* `same[A](value: A)`: A matcher which will accept only the same instance as the given value.\n* `isNull[A]`: A matcher which will accept only null values.\n* `isNotNull[A]`: A matcher which will accept only non-null values.\n* `contains(substring: String)`: A matcher which will accept only strings which contain the given substring.\n* `matches(pattern: Regex)`: A matcher which will accept only strings which match the given pattern.\n* `endsWith(suffix: String)`: A matcher which will accept only strings which end with the given suffix.\n* `startsWith(prefix: String)`: A matcher which will accept only strings which start with the given prefix.\n\n**WARNING**: Since the matchers are really Java under the hood, they do not\nunderstand Scala default arguments. If you are matching against a method with\ndefault arguments, you *must* specify the default arguments as well\n(Scala calls the method with `null` if the default is used.)\n\n### Responding to invocations with answersWith\n\nIf you have a mock, you can invoke arbitrary behavior when it is called\nby using `answersWith`. This calls a function whenever the mock is used.\n\nThis can let you use a fake implementation for the mocked object. It's\nuseful for implementing enough of the functionality to make your code work,\nor for doing some more advanced checks than normal matchers allow.\n\n```scala\nmyMock.get(any[String]).answersWith { f =\u003e\n  val stringArg = f.getArguments.toSeq.head.asInstanceOf[String]\n  println(\"I was called with \" + stringArg)\n  false // your return value\n}\n```\n\n### Argument Capture\n\nSimplespec supports Mockito's [ArgumentCaptor](http://docs.mockito.googlecode.com/hg/org/mockito/ArgumentCaptor.html) to capture\narguments:\n\n```scala\nclass FooClass {\n  def concatMethod(x: String, y: Int): String = x + y.toString\n}\nval arg3 = captor[String]\nval arg4 = captor[Int]\nval fooMock = mock[FooClass]\nfooMock.concatMethod(\"foo\", 1)\n\nverify.one(fooMock).concatMethod(arg3.capture(), arg4.capture())\narg3.getValue().must(be(\"foo\"))\narg4.getValue().must(be(1))\n```\n\n### Mock Verification\n\nTODO: Document this.\n\nScalaCheck\n----------\n\nSimpleSpec includes helpers for integrating ScalaCheck properties into\nyour tests, with the `hold` and `prove` matchers.\n\n```scala\nclass StringPropertySpec extends Spec {\n  import org.scalacheck.Prop._\n\n  class `String operations` {\n    @Test def startsWith {\n      forAll((a: String, b: String) =\u003e (a+b).startsWith(a)).must(hold)\n    }\n\n     @Test def concatenate {\n      forAll((a: String, b: String) =\u003e\n        (a+b).length \u003e a.length \u0026\u0026 (a+b).length \u003e b.length\n      ).must(hold)\n    }\n\n    @Test def substring {\n      forAll((a: String, b: String, c: String) =\u003e\n        (a+b+c).substring(a.length, a.length+b.length) == b\n      ).must(hold)\n    }\n  }\n}\n```\n\nThis is very convenient, since you may mix property and non-property\ntests freely, and produce test reports \u0026 code coverage for your\nScalaCheck properties.\n\nLicense\n-------\n\nCopyright (c) 2010-2012 Coda Hale\n\nCopyright (c) 2012-2014 Simple Finance Technology\n\nPublished under The MIT License, see [`LICENSE.md`](LICENSE.md)\n","funding_links":[],"categories":["\u003ca name=\"Scala\"\u003e\u003c/a\u003eScala"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSimpleFinance%2Fsimplespec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSimpleFinance%2Fsimplespec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSimpleFinance%2Fsimplespec/lists"}