From 4c0f475beb0f4c445d55f46670a1b6d8dcd9b129 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 25 May 2019 20:22:41 +0300 Subject: Add: first rough draft of fft-docgen --- fft-docgen | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ muck.md | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ muck.yaml | 32 +++++++++++++++ 3 files changed, 289 insertions(+) create mode 100755 fft-docgen create mode 100644 muck.md create mode 100644 muck.yaml diff --git a/fft-docgen b/fft-docgen new file mode 100755 index 0000000..6dd7ee9 --- /dev/null +++ b/fft-docgen @@ -0,0 +1,124 @@ +#!/bin/env python3 + +import copy +import re +import sys + +import CommonMark_bkrs as CommonMark +import yaml + +def format_keyword(line): + words = line.split(' ') + keyword = words[0] + return '**{}** '.format(keyword) + line[len(keyword):] + +def format_scenario_step(bind, line): + for b in bind: + m = re.match(b['pattern'], line, re.I) + if m and m.end() == len(line): + n = len(m.groups()) + if n > 0: + end = 0 + parts = [] + for i in range(1, n+1): + parts.append(line[end:m.start(i)]) + thispart = line[m.start(i) : m.end(i)] + parts.append('_{}_'.format(thispart)) + end = m.end(i) + line = ''.join(parts) + line[m.end(n):] + + if not line.strip(): + return line + return format_keyword(line) + +def format_fable_snippet(bind, lines): + return [format_scenario_step(bind, line) for line in lines] + +def is_fable_snippet(o): + prefix = "```fable\n" + return o.t == 'FencedCode' and o.info == 'fable' + +def is_heading(o): + return o.t =='ATXHeader' + +def write_document(bind, f, o): + pass + +def write_atxheader(bind, f, o): + f.write('{} {}\n\n'.format('#' * o.level, ' '.join(o.strings))) + +def write_setextheader(bind, f, o): + chars = { + 1: '=', + 2: '-', + } + c = chars[o.level] + f.write('{}\n{}\n\n'.format(' '.join(o.strings), c * 72)) + +def write_paragraph(bind, f, o): + for s in o.strings: + f.write('{}\n'.format(s)) + f.write('\n') + +def write_fable_snippet(bind, f, o): + for line in format_fable_snippet(bind, o.strings[1:]): + f.write('> {} \n'.format(line)) + f.write('\n') + +def write_not_fable_snippet(bind, f, o): + fence = o.fence_char * o.fence_length + lang = o.strings[0] + f.write('{}{}\n'.format(fence, lang)) + for line in o.strings[1:]: + f.write('{}\n'.format(line)) + f.write('{}\n'.format(fence)) + f.write('\n') + +def write_fencedcode(bind, f, o): + if is_fable_snippet(o): + write_fable_snippet(bind, f, o) + else: + write_not_fable_snippet(bind, f, o) + +def write_horizontalrule(bind, f, o): + f.write('---\n') + +writers = { + 'Document': write_document, + 'ATXHeader': write_atxheader, + 'SetextHeader': write_setextheader, + 'Paragraph': write_paragraph, + 'FencedCode': write_fencedcode, + 'HorizontalRule': write_horizontalrule, +} + +def write(bind, f, o): + if o.t not in writers: + debug('{} not known'.format(repr(o.t))) + return + writer = writers[o.t] + writer(bind, f, o) + +def walk(o, func): + func(o) + for c in o.children: + walk(c, func) + +def debug(msg): + sys.stderr.write('DEBUG: {}\n'.format(msg)) + sys.stderr.flush() + +debug('reading bindings') +bindings = yaml.safe_load(open(sys.argv[1])) + +debug('reading inputs') +text = ''.join(open(filename).read() for filename in sys.argv[2:]) + +debug('parse') +parser = CommonMark.DocParser() +ast = parser.parse(text) + +debug('output') +walk(ast, lambda o: write(bindings, sys.stdout, o)) + +debug('ok') diff --git a/muck.md b/muck.md new file mode 100644 index 0000000..d29319c --- /dev/null +++ b/muck.md @@ -0,0 +1,133 @@ +--- +title: Muck acceptance tests v2 +author: Lars Wirzenius / The Ick project +... + +Introduction +============================================================================= + +Muck is a persistent in-memory JSON store with an HTTP API and +advanced access control using signed JWT access tokens. This document +presents its automated acceptance tests, using a (for now +hypothetical) language similar to the Gherkin langauge implemented by +Cucumber. + +A happy path scenario +============================================================================= + +This scenario does some basic resource management via the Muck API. + +Start Muck. This also sets up access to it for the user by getting an +access token, which will be used for all requests. + +```fable +given a running Muck +``` + +Check server status. + +```fable +then there are no resources in Muck +``` + +Create a simple resource. Remember its id. + +```fable +given I am tomjon +when I create a resource {"foo": "bar"} +then there is 1 resource in Muck +and remember the resource id as ID +and remember the resource revision as REV1 +``` + +Retrieve the resource. + +```fable +when I fetch resource ID +then I get {"foo": "bar"} +and it is mine +and it has revision REV1 +``` + +Make sure another user can't retreive, update, or delete the resource. + +```fable +given I am verence +when I fetch resource ID +then it doesn't exist + +when I update ID, revision REV1, with {"foo": "somethingelse"} +then it doesn't exist + +when I delete ID +then it doesn't exist +``` + +Update the resource. + +```fable +given I am tomjon +when I update ID, revision wrong, with {"foo": "somethingelse"} +then it doesnt't work + +when I update ID, revision REV1, with {"foo": "somethingelse"} +then it works +and remember the resource revision as REV2 +``` + +Check the resource has been updated. + +```fable +when I fetch resource ID +then I get {"foo": "somethingelse"} +and it is mine +and it has revision REV2 +``` + +Restart Muck. The resource should still exist. + +```fable +when Muck is restarted +and I fetch resource ID +then I get {"foo": "somethingelse"} +and it is mine +and it has revision REV2 +``` + +Search for the resource. First with a condition that is no longer +true. + +```fable +when I search for foo being bar +then there are no matches +``` + +Now search for the correct value. + +```fable +when I search for foo being somethingelse +then I only get resource ID +``` + +Delete the resource. + +```fable +when I delete ID +then it works +``` + + +```fable +when I fetch resource ID +then it doesn't exist +``` + +Restart Muck again. The resource should not exist. + +```fable +when Muck is restarted +and I fetch resource ID +then it doesn't exist +``` + +All done. diff --git a/muck.yaml b/muck.yaml new file mode 100644 index 0000000..afc7249 --- /dev/null +++ b/muck.yaml @@ -0,0 +1,32 @@ +- pattern: when I fetch resource (?P\S+) +- pattern: and I fetch resource (?P\S+) + +- pattern: then it has revision (?P\S+) +- pattern: and it has revision (?P\S+) + +- pattern: then it is mine +- pattern: and it is mine + +- pattern: then remember the resource id as (?P\S+) +- pattern: and remember the resource id as (?P\S+) + +- pattern: then remember the resource revision as (?P\S+) +- pattern: and remember the resource revision as (?P\S+) + +- pattern: given I am (?P\S+) +- pattern: given a running Muck +- pattern: then I only get resource (?P\S+) +- pattern: then I get (?P.+) +- pattern: "then it doesn't exist" +- pattern: then it works +- pattern: then there are no resources in Muck + +- pattern: then there is (?P\d+) resource in Muck +- pattern: then there are (?P\d+) resources in Muck + +- pattern: then there are no matches +- pattern: when I create a resource (?P.+) +- pattern: when I delete (?P\S+) +- pattern: when I search for (?P\S+) being (?P.+) +- pattern: when I update (?P\S+), revision (?P\S+), with (?P.+) +- pattern: when Muck is restarted -- cgit v1.2.1