Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generates Elixir specs #24

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Downloaded/installed as part of setup - OS specific
bin/utils/oq

spec/generated

# Compiled source
*.com
Expand Down Expand Up @@ -45,19 +46,19 @@ Thumbs.db
# Elixir

# The directory Mix will write compiled artifacts to.
*-ex/_build/
*/_build/

# If you run "mix test --cover", coverage assets end up here.
*-ex/cover/
*/cover/

# The directory Mix downloads your dependencies sources to.
*-ex/deps/
*/deps/

# Where 3rd-party dependencies like ExDoc output generated docs.
*-ex/doc/
*/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
*-ex/.fetch
*/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
Expand All @@ -69,17 +70,17 @@ erl_crash.dump
npm-debug.log

# The directory NPM downloads your dependencies sources to.
*-ex/assets/node_modules/
*/assets/node_modules/

# Since we are building assets from assets/,
# we ignore priv/static. You may want to comment
# this depending on your deployment strategy.
*-ex/priv/static/
*/priv/static/

# Files matching config/*.secret.exs pattern contain sensitive
# data and you should not commit them into version control.
#
# Alternatively, you may comment the line below and commit the
# secrets files as long as you replace their contents by environment
# variables.
*-ex/config/*.secret.exs
*/config/*.secret.exs
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
ruby 2.6.5
erlang 22.3
elixir 1.10.2-otp-22
51 changes: 36 additions & 15 deletions bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,68 @@ export OQ_VERSION="1.0.2"

# Setup ASDF version manager and install deps
setup_asdf() {
_info_banner "[ASDF] Setting up"
local prefix="[ASDF]"

_info_banner "${prefix} Setting up"

# Version manager for multiple languages
_prompt_for_command_install "asdf"

_info_message "Installing/Updating ASDF dependencies"
(asdf install && _success_message "Success - ASDF dependencies up to date") || \
_error_message "Failed to update ASDF dependencies"
(asdf install && _success_message "${prefix} Success: dependencies up to date") || \
_error_message "${prefix} Failed to update dependencies"
}

# Setup Ruby dependencies (used for Danger and generating templated specs)
setup_ruby() {
local prefix="[Ruby]"

_info_banner "${prefix} Setting up"

_info_message "${prefix} Installing/Updating RubyGems"
(bundle install && _success_message "${prefix} Success: RubyGems up to date") || \
_error_message "${prefix} Failed to update RubyGems"
}

_elixir_update() {
local subpath="${1?}"
local prefix="[${subpath}]"

# Setup dependencies for Elixir
setup_elixir() {
_info_banner "[Elixir] Setting up"
pushd statifier-ex 1>/dev/null
_info_banner "${prefix} Updating Elixir dependencies"

pushd "${subpath}" 1>/dev/null
# shellcheck disable=SC1010
mix do deps.get, compile

popd 1>/dev/null
_success_message "[Elixir] All up to date!"

_success_message "${prefix} Success: Elixir dependencies up to date"
}

# Setup dependencies for statifier-ex
setup_statifier_ex() {
_elixir_update statifier-ex
}

# Setup dependencies for Spec
setup_spec() {
_info_banner "[Spec] Setting up"
_elixir_update spec

# Working with YAML, XML and JSON files
_prompt_for_oq_install

_success_message "[Spec] All up to date!"
# # Working with YAML, XML and JSON files
# _prompt_for_oq_install
}


# Setup entire project. First global dependencies, then each package.
setup_project() {
_info_banner "Setting up Statifier"

# Global Setup
setup_asdf
setup_ruby

# Package specific
setup_spec
setup_elixir
setup_statifier_ex

_success_banner "Project successfully setup"
}
Expand Down
11 changes: 11 additions & 0 deletions bin/spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

set -u # raise an error on use of uninitialized variable
set -e # exit after the first error

# Wrapper around using the spec/Makefile using make v4

trap "popd 1>/dev/null" EXIT
pushd "spec" 1> /dev/null

gmake "$@"
47 changes: 47 additions & 0 deletions spec/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Your Makefiles are wrong: https://tech.davis-hansson.com/p/make/
# Self Documented Makefile: https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
# Bash strict mode: http://redsymbol.net/articles/unofficial-bash-strict-mode/

SHELL := bash
.ONESHELL:
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
HELP_TASK_WIDTH := 20

ifeq ($(origin .RECIPEPREFIX), undefined)
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
endif
.RECIPEPREFIX = >

.DEFAULT_GOAL := help

help: ## Displays help message describing each task
> @printf "\n%s\n\n" "Statifier Spec Make Tasks"
> @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-${HELP_TASK_WIDTH}s\033[0m %s\n", $$1, $$2}'
# Don't look for this on the filesystem
.PHONY: help

generate: generated/.elixir ## Generate all specs
> @echo "Done!"
# Don't look for this on the filesystem
.PHONY: generate

generated/.elixir: generated/
> @mix run generate.exs elixir $@

generated/:
> @mkdir -p generated

# w3c/.manifest: w3c/manifest.xml w3c_manifest.exs
# > @mix run w3c_manifest.exs w3c/manifest.xml $@ $(W3C_SUITE)

clean: ## Cleanup (remove) all generated files.
> @rm -rf generated

collect: $(shell find . -type d | grep '[0-9][0-9][0-9]' | awk '{printf $1 "/all.yml"}') ## Collect all sub specs into the **/*__all.yml file
> @echo
> @echo "hi"
# Don't look for this on the filesystem
.PHONY: help
12 changes: 12 additions & 0 deletions spec/generate.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule SpecGenerator do
def process(language, touchfile) do
full_touchfile = Path.expand(touchfile, ".")

IO.puts("Hi from Elixir: #{language} #{full_touchfile}")

File.touch!(full_touchfile)
end
end

[language, touchfile] = System.argv()
SpecGenerator.process(language, touchfile)
45 changes: 45 additions & 0 deletions spec/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
defmodule Statifier.MixProject do
use Mix.Project

def project do
[
app: :statifier_spec,
version: "0.1.0",
elixir: "~> 1.8",
start_permanent: Mix.env() == :prod,
docs: [extras: ["README.md"]],
description: description(),
# package: package(),
deps: deps()
]
end

def description, do: "Statifier Spec Generator"

# def package do
# [
# name: :statifier_spec,
# maintainers: ["JohnnyT"],
# licenses: ["MIT"],
# docs: [extras: ["README.md"]],
# links: %{"GitHub" => "https://github.com/riddler/statifier-ex"}
# ]
# end

# # Run "mix help compile.app" to learn about applications.
# def application do
# [
# extra_applications: [:logger]
# ]
# end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
{:ex_doc, ">= 0.0.0", only: :dev},
{:liquid, "~> 0.9"},
{:yaml_elixir, "~> 2.4"}
]
end
end
25 changes: 25 additions & 0 deletions spec/mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
%{
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
"ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"},
"gettext": {:hex, :gettext, "0.17.4", "f13088e1ec10ce01665cf25f5ff779e7df3f2dc71b37084976cf89d1aa124d5c", [:mix], [], "hexpm", "3c75b5ea8288e2ee7ea503ff9e30dfe4d07ad3c054576a6e60040e79a801e14d"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
"jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"},
"liquid": {:hex, :liquid, "0.9.1", "eef4797f4b8b1cdd14c44d6dcd52bb49df9caf6bcf5dacfd61911fba8b6a628d", [:mix], [{:timex, "~> 3.0", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "0472e078709036d0d31a82c6542d559cdad81552c40fb51745e108d4785db8df"},
"makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49736fe5b66a08d8575bf5321d716bac5da20c8e6b97714fec2bcd6febcfa1f8"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "f354efb2400dd7a80fd9eb6c8419068c4f632da4ac47f3d8822d6e33f08bc852"},
"tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
"yamerl": {:hex, :yamerl, "0.8.0", "8214cfe16bbabe5d1d6c14a14aea11c784b9a21903dd6a7c74f8ce180adae5c7", [:rebar3], [], "hexpm", "010634477bf9c208a0767dcca89116c2442cf0b5e87f9c870f85cd1c3e0c2aab"},
"yaml_elixir": {:hex, :yaml_elixir, "2.4.0", "2f444abc3c994c902851fde56b6a9cb82895c291c05a0490a289035c2e62ae71", [:mix], [{:yamerl, "~> 0.7", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "4e25a6d5c873e393689c6f1062c5ec90f6cd1be2527b073178ae37eae4c78bee"},
}
69 changes: 69 additions & 0 deletions spec/templates/ex/statechart_test.exs.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# AUTOGENERATED FILE - DO NOT EDIT

defmodule Statifier.Spec.<%= spec.specid %>Test do
use ExUnit.Case, async: true

@moduletag spec_id: "<%= spec.specid %>"
@moduletag spec_group: "<%= spec.specgroup %>"
@moduletag spec_subject: "Statechart"
@moduletag spec_description: """
<%= spec.description %>
"""
@moduletag spec_statechart: <%= spec.statechart | elixir_map %>

{% comment %}
alias Statifier.Statechart

setup_all do
%{instructions: <%= instructions %>}
end
<% tests.each do |test| %>
test "<%= test["name"] %>", context do
predicate_context = <% if test["context"].nil? %>nil<% else %><%= elixir_hash test["context"] %><% end %>
expected_result = <% if test["result"].nil? %>nil<% else %><%= test["result"] %><% end %>

result = Predicator.Evaluator.execute context[:instructions], predicate_context
assert expected_result == result
#assert_empty e.stack
end
{% endcomment %}
<% end %>
end
{% comment %}
defmodule Statifier.Spec. do
use ExUnit.Case

alias Statifier.{Statechart, StateDef}

# Definied in test helper
alias Statifier.Spec

test "building basic statechart" do
test_path = Path.join(File.cwd!(), "test/fixtures/basic.yml")

{:ok, test_config} = YamlElixir.read_from_file(test_path)

sc = Statechart.build(test_config["statechart"])

assert %Statechart{
name: "Valid Single State",
states: [%StateDef{id: "greeting"} | _rest]
} = sc
end

# This corresponds to the <scxml> element defined here:
# https://www.w3.org/TR/scxml/#scxml

# A conformant SCXML document must have at least one <state>, <parallel> or
# <final> child.
test "conformance: at least one state" do
spec = Spec.from_fixture("basic.yml")

sc =
Statechart.build(spec.statechart)
|> Statechart.validate()

assert %Statechart{conformant: true} = sc
end
end
{% endcomment %}
Loading