Commit 67c324e8 authored by Drew's avatar Drew

Documentation support

parent 563b3f59
Pipeline #2239 passed with stages
in 2 minutes and 5 seconds
.atllbuild
bin
*.sublime-workspace
docs/_build
......@@ -35,6 +35,20 @@ linux:
- autoscale-linux
image: drewcrawford/swift:latest
documentation:
stage: package
script:
- cd docs
- make html
tags:
- autoscale-linux
artifacts:
paths:
- _build/html
image: drewcrawford/anarchy-sphinx:latest
osxcorepackage:
stage: package
script:
......
......@@ -16,9 +16,11 @@
public protocol CarolineTest: class {
///Implement the test behavior here
func test()
///The test should be skipped
///Return true iff the test should be skipped.
///This method is optional.
var skip: Bool { get }
///Fail on pass, pass on failure
///If true, expect a failure for this test instead of a pass.
///This method is optional.
var expectFailure: Bool { get }
}
......
......@@ -42,6 +42,8 @@ private func compare<T: SequenceType where T.Generator.Element: Equatable>(_ a:
#endif
extension CarolineTest {
///Fail the test.
///- parameter message: A reason for failure
public final func fail(_ message: String = "Test failed", file: String = #file, line: Int = #line) {
var state = CarolineState(test: self)
if self.expectFailure {
......@@ -55,12 +57,16 @@ extension CarolineTest {
}
#if swift(>=3.0)
///Assert a boolean expression
///- parameter condition: A condition to assert
///- message: A reason for failure
public final func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if !condition() {
self.fail(message(), file: file, line: line)
}
}
#else
///- noindex: true
public final func assert(@autoclosure _ condition: () -> Bool, @autoclosure _ message: () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if !condition() {
self.fail(message(), file: file, line: line)
......@@ -71,42 +77,54 @@ extension CarolineTest {
//Equatable and SequenceType<Equatable>
#if swift(>=3.0)
///Assert that two objects are equal
///- parameter message: A reason for failure
public final func assert<T: Equatable>(_ a: T, equals b: T, _ message: @autoclosure () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if a != b {
self.fail("\(message()) - \(a) != \(b)", file: file, line: line)
}
}
///Assert that two objects aren't equal
///- parameter message: A reason for failure
public final func assert<T: Equatable>(_ a: T, notEqual b: T, _ message: @autoclosure () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if a == b {
self.fail("\(message()) - \(a) == \(b)", file: file, line: line)
}
}
///Assert that two sequences are equal
///- parameter message: A reason for failure
public final func assert<T:Sequence where T.Iterator.Element: Equatable>(_ a: T, equals b: T, _ message: @autoclosure () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if !compare(a,b) {
self.fail("\(message()) - \(a) != \(b)", file: file, line: line)
}
}
///Assert that two sequences aren't equal
///- parameter message: A reason for failure
public final func assert<T:Sequence where T.Iterator.Element: Equatable>(_ a: T, notEqual b: T, _ message: @autoclosure () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if compare(a,b) {
self.fail("\(message()) - \(a) == \(b)", file: file, line: line)
}
}
#else
///- noindex: true
public final func assert<T: Equatable>(_ a: T, equals b: T, @autoclosure _ message: () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if a != b {
self.fail("\(message()) - \(a) != \(b)", file: file, line: line)
}
}
}
///- noindex: true
public final func assert<T: Equatable>(_ a: T, notEqual b: T, @autoclosure _ message: () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if a == b {
self.fail("\(message()) - \(a) == \(b)", file: file, line: line)
}
}
///- noindex: true
public final func assert<T:SequenceType where T.Generator.Element: Equatable>(_ a: T, equals b: T, @autoclosure _ message: () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if !compare(a,b) {
self.fail("\(message()) - \(a) != \(b)", file: file, line: line)
}
}
///- noindex: true
public final func assert<T:SequenceType where T.Generator.Element: Equatable>(_ a: T, notEqual b: T, @autoclosure _ message: () -> String = "Assertion failed", file: String = #file, line: Int = #line) {
if compare(a,b) {
self.fail("\(message()) - \(a) == \(b)", file: file, line: line)
......
......@@ -57,7 +57,7 @@ func performXcodeIntegration() -> Bool {
try! xcTestFile.write(file: generatedFilePath)
if !paths.contains(generatedFilePath) {
print("You need to add \(generatedFilePath) to your Xcode Project.")
print("error: You need to add CarolineXCTest.swift to your Xcode Project.")
exit(1)
}
......
Caroline Introduction
;;;;;;;;;;;;;;;;;;;;;;
Why Caroline?
=====================
Caroline has many key advantages over other testing frameworks.
Pure Swift
+++++++++++++++++++
Caroline is 100% Swift. Its only non-Swift dependency is libc, which makes it highly portable to any UNIX-like OS.
No Legacy
+++++++++++++++++++
Caroline doesn't need to maintain backwards compatibility with anything and so it has clean, Swifty APIs.
Caroline Everywhere
+++++++++++++++++++
Caroline runs on Swift 2 & 3, on iOS, macOS, and even Linux. And it implements the same API everywhere.
Test Discovery
+++++++++++++++++++
Caroline automatically discovers your tests, and you don't need to maintain an `allTests` list anymore.
Great Integrations
+++++++++++++++++++
Caroline is ready to roll with Xcode, `AnarchyTools <http://www.anarchytools.org/>`_, or anything in-between.
If you're using XCTest already, Caroline can run side-by-side with your existing XCTest tests, allowing you to try Caroline or incrementally migrate tests to Caroline as it makes sense for you. Caroline can even run entirely inside XCTest, going anywhere XCTest goes, including Xcode Server, `xcodebuild`, AWS Device Farm, and more.
If you're not using XCTest, Caroline has a great standalone mode that builds *one executable* including all runners, test frameworks, tests, and other code so you can just *run it from the commandline* from other tooling.
Clear Design
+++++++++++++++++++
The author is an expert in iOS/Swift continuous testing, and this is the tool he always wanted to build.
Caroline Editions
=====================
Caroline comes in two editions:
* Caroline Core, a free, permissively-licensed testing library, with all the classic testing features.
* Caroline Pro, a commercially-supported advanced testing engine with many novel features. CarolinePro is open-source, but under a fairly restrictive license. Commercial licensing is available from the author.
.. note::
Caroline Pro is not included in this preview.
Writing your first test
-------------------------
Writing tests in Caroline is a breeze. Here's an example:
.. code:: swift
import CarolineCore
class Foo: CarolineTest {
func test() {
self.assert(true)
}
}
Examples
------------------------
Expecting a test to fail
=========================
.. code:: swift
import CarolineCore
class Foo: CarolineTest {
func test() {
self.assert(false)
}
let expectedFailure = true
}
Skipping tests
=========================
.. code:: swift
import CarolineCore
class Foo: CarolineTest {
func test() {
self.assert(false)
}
let skip = true
}
Comparing two values
=========================
.. code:: swift
import CarolineCore
class Foo: CarolineTest {
func test() {
self.assert(1, equals: 1)
}
}
.. code:: swift
import CarolineCore
class Foo: CarolineTest {
func test() {
self.assert(1, notEqual: 1)
}
}
Installation
=====================
Caroline has two parts; the :term:`static tool` and the :term:`framework`.
.. glossary::
static tool
A program that discovers tests, performs code generation, and integrates with your build environment. This runs on your development machine.
framework
The Caroline test engine itself, compiled and linked with your code.
Installing the static tool
--------------------------
.. todo::
install static tool
Installing the framework
--------------------------
Framework installation depends on how you build your software.
For projects built with Xcode
_________________________________
With Xcode, we run the Caroline engine inside a single XCTest. This lets you mix and match Caroline and XCTest projects in order to try out Caroline or incrementally migrate your code. It also means Caroline will go everywhere XCTest goes, including running on devices, your CI system, Xcode Server, AWS Device Farm, and much more.
.. todo::
where do the users download the framework for xcode?
1. Drag the Caroline framework into your project
.. raw:: html
<video controls src="_static/drag-framework.m4v" width="75%"></video>
2. Create a build script phase in your test target with these contents:
.. code:: bash
caroline-static-tool
Place it at the top of the build phases, just below "Target Dependencies".
.. raw:: html
<video controls src="_static/run-script-phase.m4v" width="75%"></video>
.. todo::
Make sure caroline-static-tool is actually named this
.. warning::
Make sure you create this script phase in your **test target**, not your **app target**.
3. Press Cmd-U. The test will fail to build, but a new source file `CarolineXCTest.swift` will be generated.
4. Add the sourcefile to your test target.
.. raw:: html
<video controls src="_static/carolinexctest.m4v" width="75%"></video>
5. Press Cmd-U. Your tests should run and pass successfully.
Staying up to date
******************************
You can download new Caroline from the [releases page](https://code.sealedabstract.com/drewcrawford/Caroline/tags).
Caroline can also be updated with the `atpm` package manager.
.. todo::
Updating caroline via AT
For projects built with AnarchyTools
______________________________________
1. Add the Caroline source to your external-packages in :code:`build.atpkg`
.. code:: clojure
:external-packages [
{
:url "https://code.sealedabstract.com/drewcrawford/Caroline.git"
:versions [">=0.1"]
}
]
2. Create a task to generate your tests.
.. code:: clojure
:gen-tests {
:tool "shell"
:core "${collect_sources:build-tests}"
:script "caroline-static-tool --core ${collect_sources:build-tests} > NaOHTests/main.swift"
}
3. Create a task to build your tests.
.. code:: clojure
:build-tests {
:tool "atllbuild"
:sources ["MyTestSources/**.swift"]
:name "tests"
:output-type "executable"
:dependencies ["Caroline.core" "gen-tests" "default"]
:link-with-product ["CarolineCore.a" "MyLibrary.a"]
:publish-product true
}
.. note::
Make sure you replace :code:`default` with the task that builds the software you need to test. The convention is to use :code:`default` for that, but you may have chosen a different name.
4. Create a task to run your tests.
.. code:: clojure
:check {
:tool "shell"
:script "bin/tests"
:dependencies ["build-tests"]
}
5. Run :code:`atbuild check` in Terminal. Your tests should pass.
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
PROJECT_NAME=Caroline
export LC_ALL=C.UTF-8
export LANG=C.UTF-8
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " epub3 to make an epub3"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
@echo " dummy to check syntax errors of document sources"
@echo " dashdoc to make Dash docset"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dashdoc
dashdoc:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) -D 'html_sidebars.**=""' $(BUILDDIR)/dashdoc
doc2dash -v -n $(PROJECT_NAME) -d $(BUILDDIR)/ -f -I index.html -j $(BUILDDIR)/dashdoc
@echo
@echo "Build finished. The Docset is in $(BUILDDIR)/$(PROJECT_NAME).docset."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Caroline.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Caroline.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Caroline"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Caroline"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: epub3
epub3:
$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
@echo
@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
.PHONY: dummy
dummy:
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
@echo
@echo "Build finished. Dummy builder generates no files."
Test-writing reference
------------------------
Caroline tests conform to the :swift:protocol:`CarolineTest` protocol.
.. autoprotocol:: CarolineTest
:members:
There is no required base class for tests, so you can subclass the object being tested, or declare your own class.
Assertion functions
+++++++++++++++
By the magic of protocol extensions, your test object has the following assertion functions installed:
.. autoextension:: CarolineTest
:members:
:only-with-members: assert
\ No newline at end of file
dd {
margin-left: 30px;
}
code {
color: #29abe0;
}
code.descclassname {
color: rgba(41, 171, 224, 0.72);
}
\ No newline at end of file
{# Import the theme's layout. #}
{% extends "!layout.html" %}
{# Custom CSS overrides #}
{% set bootswatch_css_custom = ['_static/my-styles.css'] %}
\ No newline at end of file
This diff is collapsed.
.. Caroline documentation master file, created by
sphinx-quickstart on Thu Jun 30 19:41:21 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Caroline
====================================
Caroline is a new, pure-Swift testing framework.
.. todolist::
Contents:
====================================
.. toctree::
:maxdepth: 2
CarolineIntro
Installation
GettingStarted
TestWritingReference
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
......@@ -23,5 +23,5 @@ class Additional: CarolineTest {
func test() {
self.assert(false, "I am a bad programmer")
}
var skip : Bool { return true }
let skip = true
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment