Skip to content

Commit

Permalink
strict versionning (forbid version not handled)
Browse files Browse the repository at this point in the history
  • Loading branch information
bchamagne committed Mar 9, 2023
1 parent 74bde29 commit 9f68495
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 35 deletions.
13 changes: 8 additions & 5 deletions lib/archethic/contracts/interpreter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ defmodule Archethic.Contracts.Interpreter do
@spec parse(code :: binary()) :: {:ok, Contract.t()} | {:error, String.t()}
def parse(code) when is_binary(code) do
case version(code) do
{{0, _, _}, code_without_version} ->
{{0, 0, 1}, code_without_version} ->
Version0.parse(code_without_version)

{version = {1, _, _}, code_without_version} ->
Version1.parse(code_without_version, version)

_ ->
{:error, "@version not supported"}
end
end

Expand All @@ -44,7 +47,7 @@ defmodule Archethic.Contracts.Interpreter do
Return the version & the code where the version has been removed.
(should be private, but there are unit tests)
"""
@spec version(String.t()) :: {version(), String.t()}
@spec version(String.t()) :: {version(), String.t()} | :error
def version(code) do
regex_opts = [capture: :all_but_first]

Expand All @@ -54,17 +57,17 @@ defmodule Archethic.Contracts.Interpreter do
case Regex.run(version_attr_regex, code, regex_opts) do
nil ->
# there is a @version but syntax is invalid (probably the quotes missing)
raise "invalid @version"
:error

[capture] ->
case Regex.run(semver_regex(), capture, regex_opts) do
nil ->
# there is a @version but semver syntax is wrong
raise "invalid @version"
:error

["0", "0", "0"] ->
# there is a @version but it's 0.0.0
raise "invalid @version"
:error

[major, minor, patch] ->
{
Expand Down
17 changes: 11 additions & 6 deletions lib/archethic/contracts/interpreter/version1.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
defmodule Archethic.Contracts.Interpreter.Version1 do
@moduledoc false

alias Archethic.Contracts.Contract
alias Archethic.Contracts.ContractConditions, as: Conditions

alias Archethic.TransactionChain.Transaction

@spec parse(code :: binary(), {integer(), integer(), integer()}) :: {:error, binary()}
def parse(code, {1, _, _}), do: parse_v1(code)
@doc """
Parse the code and return the parsed contract.
"""
@spec parse(binary(), {integer(), integer(), integer()}) ::
{:ok, Contract.t()} | {:error, String.t()}
def parse(code, {1, 0, 0}) when is_binary(code) do
{:ok, %Contract{version: {1, 0, 0}}}
end

def parse(_, _), do: {:error, "@version not supported"}

@doc """
Return true if the given conditions are valid on the given constants
Expand All @@ -24,8 +33,4 @@ defmodule Archethic.Contracts.Interpreter.Version1 do
def execute_trigger(_ast, _constants) do
nil
end

defp parse_v1(code) when is_binary(code) do
{:error, "not implemented"}
end
end
63 changes: 39 additions & 24 deletions test/archethic/contracts/interpreter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,41 @@ defmodule Archethic.Contracts.InterpreterTest do
use ArchethicCase

alias Archethic.Contracts.Interpreter
alias Archethic.ContractFactory

doctest Interpreter

describe "strict versionning" do
test "should return ok if version exists" do
assert {:ok, _} = Interpreter.parse(ContractFactory.valid_version1_contract())
assert {:ok, _} = Interpreter.parse(ContractFactory.valid_version0_contract())
end

test "should return an error if version does not exist yet" do
code_v0 = ~s"""
@version "0.144.233"
#{ContractFactory.valid_version0_contract()}
"""

code_v1 = ~s"""
@version "1.377.610"
#{ContractFactory.valid_version1_contract(version_attribute: false)}
"""

assert {:error, "@version not supported"} = Interpreter.parse(code_v0)
assert {:error, "@version not supported"} = Interpreter.parse(code_v1)
end

test "should return an error if version is invalid" do
code_v0 = ~s"""
@version 12
#{ContractFactory.valid_version0_contract()}
"""

assert {:error, "@version not supported"} = Interpreter.parse(code_v0)
end
end

describe "version/1" do
test "should return 0.0.1 if there is no interpreter tag" do
code = ~s(some code)
Expand All @@ -28,30 +60,13 @@ defmodule Archethic.Contracts.InterpreterTest do
assert {{3, 105, 0}, _} = Interpreter.version(~s(\n \n @version "3.105.0" \n \n))
end

test "should raise if version is not formatted as expected" do
assert_raise RuntimeError, fn ->
Interpreter.version(~s(@version "0"))
end

assert_raise RuntimeError, fn ->
Interpreter.version(~s(@version "1"))
end

assert_raise RuntimeError, fn ->
Interpreter.version(~s(@version "0.0"))
end

assert_raise RuntimeError, fn ->
Interpreter.version(~s(@version "1.1"))
end

assert_raise RuntimeError, fn ->
Interpreter.version(~s(@version "0.0.0"))
end

assert_raise RuntimeError, fn ->
Interpreter.version(~s(@version 1.1.1))
end
test "should return error if version is not formatted as expected" do
assert :error = Interpreter.version(~s(@version "0"))
assert :error = Interpreter.version(~s(@version "1"))
assert :error = Interpreter.version(~s(@version "0.0"))
assert :error = Interpreter.version(~s(@version "1.1"))
assert :error = Interpreter.version(~s(@version "0.0.0"))
assert :error = Interpreter.version(~s(@version 1.1.1))
end
end
end
44 changes: 44 additions & 0 deletions test/support/contract_factory.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
defmodule Archethic.ContractFactory do
@moduledoc false

def valid_version1_contract(opts \\ []) do
code = ~S"""
condition inherit: [
content: true
]
condition transaction: [
uco_transfers: Map.size() > 0
]
actions triggered_by: transaction do
Contract.set_content "hello"
end
"""

if Keyword.get(opts, :version_attribute, true) do
"""
@version "1.0.0"
#{code}
"""
else
code
end
end

def valid_version0_contract() do
~S"""
condition inherit: [
content: true
]
condition transaction: [
uco_transfers: size() > 0
]
actions triggered_by: transaction do
set_content "hello"
end
"""
end
end

0 comments on commit 9f68495

Please sign in to comment.