Updates to corpus + generator.

pull/1125/head
Rick Carlino 2019-02-25 15:58:01 -06:00
parent 8b79fdd866
commit 9399ad7f27
3 changed files with 178 additions and 173 deletions

View File

@ -86,21 +86,21 @@ module CeleryScriptSettingsBag
}.map { |(name, list)| Corpus.value(name, list) } }.map { |(name, list)| Corpus.value(name, list) }
CORPUS_ENUM = { CORPUS_ENUM = {
ALLOWED_AXIS: [ALLOWED_AXIS, BAD_AXIS], ALLOWED_AXIS: [ALLOWED_AXIS, BAD_AXIS],
ALLOWED_CHANNEL_NAMES: [ALLOWED_CHANNEL_NAMES, BAD_CHANNEL_NAME], ALLOWED_CHANNEL_NAMES: [ALLOWED_CHANNEL_NAMES, BAD_CHANNEL_NAME],
ALLOWED_MESSAGE_TYPES: [ALLOWED_MESSAGE_TYPES, BAD_MESSAGE_TYPE], ALLOWED_MESSAGE_TYPES: [ALLOWED_MESSAGE_TYPES, BAD_MESSAGE_TYPE],
ALLOWED_OPS: [ALLOWED_OPS, BAD_OP], ALLOWED_OPS: [ALLOWED_OPS, BAD_OP],
ALLOWED_PACKAGES: [ALLOWED_PACKAGES, BAD_PACKAGE], ALLOWED_PACKAGES: [ALLOWED_PACKAGES, BAD_PACKAGE],
ALLOWED_PIN_MODES: [ALLOWED_PIN_MODES, BAD_ALLOWED_PIN_MODES], ALLOWED_PIN_MODES: [ALLOWED_PIN_MODES, BAD_ALLOWED_PIN_MODES],
AllowedGroupTypes: [ALLOWED_EVERY_POINT_TYPE, BAD_EVERY_POINT_TYPE], AllowedGroupTypes: [ALLOWED_EVERY_POINT_TYPE, BAD_EVERY_POINT_TYPE],
AllowedPinTypes: [ALLOWED_PIN_TYPES, BAD_PIN_TYPE], AllowedPinTypes: [ALLOWED_PIN_TYPES, BAD_PIN_TYPE],
Color: [Sequence::COLORS, MISC_ENUM_ERR], Color: [Sequence::COLORS, MISC_ENUM_ERR],
DataChangeType: [ALLOWED_CHAGES, MISC_ENUM_ERR], DataChangeType: [ALLOWED_CHAGES, MISC_ENUM_ERR],
LegalSequenceKind: [ALLOWED_RPC_NODES.sort, MISC_ENUM_ERR], LegalSequenceKind: [ALLOWED_RPC_NODES.sort, MISC_ENUM_ERR],
lhs: [ALLOWED_LHS_STRINGS, BAD_LHS], lhs: [ALLOWED_LHS_STRINGS, BAD_LHS],
PlantStage: [PLANT_STAGES, MISC_ENUM_ERR], PlantStage: [PLANT_STAGES, MISC_ENUM_ERR],
PointType: [ALLOWED_POINTER_TYPE, BAD_POINTER_TYPE], PointType: [ALLOWED_POINTER_TYPE, BAD_POINTER_TYPE],
resource_type: [ALLOWED_RESOURCE_TYPE, BAD_RESOURCE_TYPE], resource_type: [ALLOWED_RESOURCE_TYPE, BAD_RESOURCE_TYPE],
}.each { |(name, list)| Corpus.enum(name, *list) } }.each { |(name, list)| Corpus.enum(name, *list) }
def self.e(symbol) def self.e(symbol)
@ -232,7 +232,12 @@ module CeleryScriptSettingsBag
end, end,
}, },
package: { package: {
defn: [e(:ALLOWED_PACKAGES)], defn: [v(:string)],
# `package` has an ambiguous intent depending on who is using the arg
# (FBOS vs. API). Corpus-native enums cannot be used for validation
# outside of the API. If `package` _was_ declared as a native enum (rather
# than a string), it would cause false type errors in FE/FBJS.
blk: -> (node) { manual_enum(ALLOWED_PACKAGES, node, BAD_PACKAGE) },
}, },
axis: { axis: {
defn: [e(:ALLOWED_AXIS)], defn: [e(:ALLOWED_AXIS)],
@ -281,12 +286,13 @@ module CeleryScriptSettingsBag
change_ownership: { change_ownership: {
body: [:pair], body: [:pair],
tags: [:function, :network_user, :disk_user, :cuts_power, :api_writer], tags: [:function, :network_user, :disk_user, :cuts_power, :api_writer],
docs: "Not a commonly used node. May be removed without notice." blk: -> (node) { raise "Never." },
docs: "Not a commonly used node. May be removed without notice.",
}, },
channel: { channel: {
args: [:channel_name], args: [:channel_name],
tags: [:data], tags: [:data],
docs: "Specifies a communication path for log messages." docs: "Specifies a communication path for log messages.",
}, },
check_updates: { check_updates: {
args: [:package], args: [:package],
@ -294,11 +300,11 @@ module CeleryScriptSettingsBag
}, },
coordinate: { coordinate: {
args: [:x, :y, :z], args: [:x, :y, :z],
tags: [:data, :location_like] tags: [:data, :location_like],
}, },
dump_info: { dump_info: {
tags: [:function, :network_user, :disk_user, :api_writer], tags: [:function, :network_user, :disk_user, :api_writer],
docs: "Sends an info dump to server administrators for troubleshooting." docs: "Sends an info dump to server administrators for troubleshooting.",
}, },
emergency_lock: { emergency_lock: {
tags: [:function, :firmware_user, :control_flow], tags: [:function, :firmware_user, :control_flow],
@ -309,7 +315,7 @@ module CeleryScriptSettingsBag
every_point: { every_point: {
args: [:every_point_type], args: [:every_point_type],
tags: [:data, :list_like, :control_flow], tags: [:data, :list_like, :control_flow],
docs: "Experimental node used for iteration." docs: "Experimental node used for iteration.",
}, },
execute_script: { execute_script: {
args: [:label], args: [:label],
@ -503,11 +509,11 @@ module CeleryScriptSettingsBag
}, },
}.map { |(name, list)| Corpus.node(name, **list) } }.map { |(name, list)| Corpus.node(name, **list) }
HASH = Corpus.as_json HASH = Corpus.as_json
ANY_ARG_NAME = HASH[:args].pluck("name").map(&:to_s) ANY_ARG_NAME = HASH[:args].pluck("name").map(&:to_s)
ANY_NODE_NAME = HASH[:nodes].pluck("name").map(&:to_s) ANY_NODE_NAME = HASH[:nodes].pluck("name").map(&:to_s)
Corpus.enum(:LegalArgString, ANY_ARG_NAME, MISC_ENUM_ERR) Corpus.enum(:LegalArgString, ANY_ARG_NAME, MISC_ENUM_ERR)
Corpus.enum(:LegalKindString, ANY_NODE_NAME.map(&:camelize), MISC_ENUM_ERR) Corpus.enum(:LegalKindString, ANY_NODE_NAME.map(&:camelize), MISC_ENUM_ERR)
def self.no_resource(node, klass, resource_id) def self.no_resource(node, klass, resource_id)

View File

@ -1,45 +1,47 @@
WARNING_HEADER = \ WARNING_HEADER =
""" "" "
// THIS INTERFACE WAS AUTO GENERATED ON #{Date.today} // THIS INTERFACE WAS AUTO GENERATED ON #{Date.today}
// DO NOT EDIT THIS FILE. // DO NOT EDIT THIS FILE.
// IT WILL BE OVERWRITTEN ON EVERY CELERYSCRIPT UPGRADE. // IT WILL BE OVERWRITTEN ON EVERY CELERYSCRIPT UPGRADE.
""" " ""
HASH = Sequence::Corpus.as_json({}) HASH = Sequence::Corpus.as_json({})
OUTPUT = [WARNING_HEADER] OUTPUT = [WARNING_HEADER]
FILE_PATH = "latest_corpus.ts" FILE_PATH = "latest_corpus.ts"
VALUES = HASH.fetch(:values) VALUES = HASH.fetch(:values)
VALUE_PREFIX = "CS" VALUE_PREFIX = "CS"
VALUES_TPL = "export type %{name} = %{type};\n" VALUES_TPL = "export type %{name} = %{type};\n"
VALUES_OVERRIDE = HashWithIndifferentAccess.new(float: "number", integer: "number") VALUES_OVERRIDE = HashWithIndifferentAccess.new(float: "number", integer: "number")
# There are some rule exceptions when generating the Typescript corpus. # There are some rule exceptions when generating the Typescript corpus.
FUNNY_NAMES = { "Example" => "CSExample" } FUNNY_NAMES = { "Example" => "CSExample" }
ENUMS = HASH.fetch(:enums) ENUMS = HASH.fetch(:enums)
ENUM_TPL = "export type %{name} = %{type};\n" ENUM_TPL = "export type %{name} = %{type};\n"
ARGS = HASH ARGS = HASH
.fetch(:args) .fetch(:args)
.reduce(HashWithIndifferentAccess.new) do |acc, arg| .reduce(HashWithIndifferentAccess.new) do |acc, arg|
acc[arg.fetch("name").to_s] = arg acc[arg.fetch("name").to_s] = arg
acc acc
end end
NODES = HASH.fetch(:nodes) NODES = HASH.fetch(:nodes)
NODE_START = [ "export type %{camel_case}BodyItem = %{body_types};", NODE_START = ["export type %{camel_case}BodyItem = %{body_types};",
"/** %{docs} %{tag_docs} */", "/** %{snake_case}\n%{docs}\n %{tag_docs} */",
"export interface %{camel_case} {", "export interface %{camel_case} {",
" comment?: string | undefined;", " comment?: string | undefined;",
' kind: "%{snake_case}";', ' kind: "%{snake_case}";',
" args: {", ].join("\n") " args: {"].join("\n")
MIDDLE_CENTER = " %{arg_name}: %{arg_values};" MIDDLE_CENTER = " %{arg_name}: %{arg_values};"
BOTTOM_END = [ " }", BOTTOM_END = [" }",
" body?: %{camel_case}BodyItem[] | undefined;", " body?: %{camel_case}BodyItem[] | undefined;",
"}\n", ].join("\n") "}\n"].join("\n")
CONSTANT_DECLR_HACK = { CONSTANT_DECLR_HACK = {
LATEST_VERSION: Sequence::LATEST_VERSION, LATEST_VERSION: Sequence::LATEST_VERSION,
DIGITAL: CeleryScriptSettingsBag::DIGITAL, DIGITAL: CeleryScriptSettingsBag::DIGITAL,
ANALOG: CeleryScriptSettingsBag::ANALOG, ANALOG: CeleryScriptSettingsBag::ANALOG,
} }
CONSTANT_DECLR_HACK_TPL = "export const %{name} = %{value};\n" CONSTANT_DECLR_HACK_TPL = "export const %{name} = %{value};\n"
PUBLIC_NODES = [] # Filled at runtime PUBLIC_NODES = [] # Filled at runtime
PIPE = " |\n"
def emit_constants() def emit_constants()
CONSTANT_DECLR_HACK.map do |(name, value)| CONSTANT_DECLR_HACK.map do |(name, value)|
konst = CONSTANT_DECLR_HACK_TPL % { name: name, value: value } konst = CONSTANT_DECLR_HACK_TPL % { name: name, value: value }
@ -52,7 +54,7 @@ def add_to_output(string)
end end
def save! def save!
File.open(FILE_PATH, "w") { |f| f.write(OUTPUT.join("")) } File.open(FILE_PATH, "w") { |f| f.write(OUTPUT.join("")) }
puts "Saved to #{FILE_PATH}" puts "Saved to #{FILE_PATH}"
end end
@ -62,9 +64,9 @@ end
def emit_values def emit_values
output = VALUES.map do |val| output = VALUES.map do |val|
real_name = name_of(val) real_name = name_of(val)
capitalized = real_name.capitalize capitalized = real_name.capitalize
celerized = VALUE_PREFIX + capitalized celerized = VALUE_PREFIX + capitalized
FUNNY_NAMES[capitalized] = celerized FUNNY_NAMES[capitalized] = celerized
type = VALUES_OVERRIDE.fetch(real_name, real_name) type = VALUES_OVERRIDE.fetch(real_name, real_name)
VALUES_TPL % { name: celerized, type: type } VALUES_TPL % { name: celerized, type: type }
@ -77,53 +79,53 @@ end
def emit_enums def emit_enums
output = ENUMS.map do |enum| output = ENUMS.map do |enum|
name = name_of(enum) name = name_of(enum)
type = enum.fetch("allowed_values").sort.map(&:inspect).uniq.join(" | ") type = enum.fetch("allowed_values").sort.map(&:inspect).uniq.join(PIPE)
FUNNY_NAMES[name] = name FUNNY_NAMES[name] = name
ENUM_TPL % { name: name, type: type } ENUM_TPL % { name: name, type: type }
end end
.uniq .uniq
.sort .sort
add_to_output(output) add_to_output(output)
end end
def emit_nodes() def emit_nodes()
nodes = NODES.map do |node| nodes = NODES.map do |node|
tags = node.fetch("tags").sort.uniq tags = node.fetch("tags").sort.uniq
# Don't publish internal CeleryScript nodes: # Don't publish internal CeleryScript nodes:
next if tags.include?(:private) next if tags.include?(:private)
tag_list = tags.join(", ") tag_list = tags.join(", ")
name = name_of(node).to_s name = name_of(node).to_s
bodies = node bodies = node
.fetch("allowed_body_types") .fetch("allowed_body_types")
.sort .sort
.uniq .uniq
.map(&:to_s) .map(&:to_s)
.map(&:camelize) .map(&:camelize)
bt = bodies.any? ? "(#{bodies.join(" | ")})" : "never" bt = bodies.any? ? "(#{bodies.join(PIPE)})" : "never"
PUBLIC_NODES.push(name.camelize) PUBLIC_NODES.push(name.camelize)
tpl_binding = { tpl_binding = {
body_types: bt, body_types: bt,
camel_case: name.camelize, camel_case: name.camelize,
docs: node.fetch("docs"), docs: node.fetch("docs"),
snake_case: name, snake_case: name,
tag_docs: "Tag properties: #{tag_list}." tag_docs: "Tag properties: #{tag_list}.",
} }
one = NODE_START % tpl_binding one = NODE_START % tpl_binding
two = node.fetch("allowed_args").sort.map do |arg| two = node.fetch("allowed_args").sort.map do |arg|
MIDDLE_CENTER % { MIDDLE_CENTER % {
arg_name: arg.to_s, arg_name: arg.to_s,
arg_values: ARGS.fetch(arg) arg_values: ARGS.fetch(arg)
.fetch("allowed_values") .fetch("allowed_values")
.map(&:name) .map(&:name)
.map { |x| FUNNY_NAMES[x] || x.camelize } .map { |x| FUNNY_NAMES[x] || x.camelize }
.join(" | ") .join(PIPE),
} }
end
three = BOTTOM_END % tpl_binding
[one, two, three].flatten.join("\n")
end end
three = BOTTOM_END % tpl_binding
[one, two, three].flatten.join("\n")
end
.compact .compact
.uniq .uniq
.join("\n") .join("\n")
@ -131,13 +133,14 @@ def emit_nodes()
end end
def emit_misc() def emit_misc()
types = PUBLIC_NODES.sort.uniq.join(" | ") types = PUBLIC_NODES.sort.uniq.join(PIPE)
tpl = "export type CeleryNode = #{types};\n" tpl = "export type CeleryNode = #{types};\n"
add_to_output(tpl) add_to_output(tpl)
end end
emit_constants() emit_constants()
emit_values() emit_values()
emit_enums() emit_enums()
emit_nodes() emit_nodes()
emit_misc() emit_misc()
save! save!

View File

@ -1,4 +1,4 @@
require 'spec_helper' require "spec_helper"
describe CeleryScript::Checker do describe CeleryScript::Checker do
let(:device) { FactoryBot.create(:device) } let(:device) { FactoryBot.create(:device) }
@ -7,15 +7,15 @@ describe CeleryScript::Checker do
kind: "sequence", kind: "sequence",
args: { args: {
locals: Sequence::SCOPE_DECLARATION, locals: Sequence::SCOPE_DECLARATION,
version: 0 version: 0,
}, },
comment: "Properly formatted, syntactically valid sequence.", comment: "Properly formatted, syntactically valid sequence.",
body: sequence_body_for(FakeSequence.create()) body: sequence_body_for(FakeSequence.create()),
}.deep_symbolize_keys }.deep_symbolize_keys
end end
let(:tree) do let(:tree) do
CeleryScript::AstNode.new(hash) CeleryScript::AstNode.new(hash)
end end
let (:corpus) { Sequence::Corpus } let (:corpus) { Sequence::Corpus }
@ -23,10 +23,10 @@ describe CeleryScript::Checker do
let (:checker) { CeleryScript::Checker.new(tree, corpus, device) } let (:checker) { CeleryScript::Checker.new(tree, corpus, device) }
it "runs through a syntactically valid program" do it "runs through a syntactically valid program" do
outcome = checker.run! outcome = checker.run!
expect(outcome).to be_kind_of(CeleryScript::AstNode) expect(outcome).to be_kind_of(CeleryScript::AstNode)
expect(outcome.comment).to eq("Properly formatted, syntactically valid"\ expect(outcome.comment).to eq("Properly formatted, syntactically valid" \
" sequence.") " sequence.")
end end
it "handles missing args" do it "handles missing args" do
@ -51,16 +51,16 @@ describe CeleryScript::Checker do
end end
it "returns an error rather than raising one via #run()" do it "returns an error rather than raising one via #run()" do
outcome = checker.run outcome = checker.run
expect(outcome).to be_kind_of(CeleryScript::AstNode) expect(outcome).to be_kind_of(CeleryScript::AstNode)
checker.tree.body.first.args[:x] = "No longer valid" checker.tree.body.first.args[:x] = "No longer valid"
expect(checker.run).to be_kind_of(CeleryScript::TypeCheckError) expect(checker.run).to be_kind_of(CeleryScript::TypeCheckError)
end end
it 'handles wrong leaf types' do it "handles wrong leaf types" do
hash[:body][0][:args][:location][:args][:x] = "supposed to be an Integer" hash[:body][0][:args][:location][:args][:x] = "supposed to be an Integer"
result = checker.run result = checker.run
expect(result.message).to eq("Expected leaf 'x' within 'coordinate' to be "\ expect(result.message).to eq("Expected leaf 'x' within 'coordinate' to be " \
"one of: [Integer, Float] but got String") "one of: [Integer, Float] but got String")
end end
@ -76,10 +76,8 @@ describe CeleryScript::Checker do
{ kind: "execute", args: { sequence_id: 0 } }, { kind: "execute", args: { sequence_id: 0 } },
] ]
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?) expect(chk.valid?).to be false
.to be false expect(chk.error.message).to eq("missing a sequence selection for `execute` block.")
expect(chk.error.message)
.to eq("missing a sequence selection for `execute` block.")
end end
it "validates peripheral presence" do it "validates peripheral presence" do
@ -91,13 +89,13 @@ describe CeleryScript::Checker do
kind: "named_pin", kind: "named_pin",
args: { args: {
pin_type: "Peripheral", pin_type: "Peripheral",
pin_id: 0 pin_id: 0,
} },
}, },
pin_mode: CeleryScriptSettingsBag::ANALOG, pin_mode: CeleryScriptSettingsBag::ANALOG,
label: "FOO" label: "FOO",
} },
} },
] ]
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
@ -109,14 +107,14 @@ describe CeleryScript::Checker do
{ {
kind: "read_pin", kind: "read_pin",
args: { args: {
pin_mode: 0, pin_mode: 0,
label: "pin", label: "pin",
pin_number: { pin_number: {
kind: "named_pin", kind: "named_pin",
args: { pin_type: "Not correct", pin_id: 1 } args: { pin_type: "Not correct", pin_id: 1 },
} },
} },
} },
] ]
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
@ -132,10 +130,10 @@ describe CeleryScript::Checker do
label: "pin", label: "pin",
pin_number: { pin_number: {
kind: "named_pin", kind: "named_pin",
args: { pin_type: "Peripheral", pin_id: 900 } args: { pin_type: "Peripheral", pin_id: 900 },
} },
} },
} },
] ]
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
@ -151,10 +149,10 @@ describe CeleryScript::Checker do
pin_mode: 0, pin_mode: 0,
pin_number: { pin_number: {
kind: "named_pin", kind: "named_pin",
args: { pin_type: ["BoxLed3", "BoxLed4"].sample, pin_id: 41 } args: { pin_type: ["BoxLed3", "BoxLed4"].sample, pin_id: 41 },
} },
} },
} },
] ]
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be true expect(chk.valid?).to be true
@ -169,17 +167,16 @@ describe CeleryScript::Checker do
pin_mode: CeleryScriptSettingsBag::ANALOG, pin_mode: CeleryScriptSettingsBag::ANALOG,
pin_number: { pin_number: {
kind: "named_pin", kind: "named_pin",
args: { pin_type: ["BoxLed3", "BoxLed4"].sample, pin_id: 41 } args: { pin_type: ["BoxLed3", "BoxLed4"].sample, pin_id: 41 },
} },
} },
} },
] ]
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
expect(chk.error.message).to include(CeleryScriptSettingsBag::CANT_ANALOG) expect(chk.error.message).to include(CeleryScriptSettingsBag::CANT_ANALOG)
end end
it 'gives human-friendly names to "BoxLed3", "BoxLed4"' do it 'gives human-friendly names to "BoxLed3", "BoxLed4"' do
hash[:body] = [ hash[:body] = [
{ {
@ -189,31 +186,29 @@ describe CeleryScript::Checker do
pin_mode: CeleryScriptSettingsBag::DIGITAL, pin_mode: CeleryScriptSettingsBag::DIGITAL,
pin_number: { pin_number: {
kind: "named_pin", kind: "named_pin",
args: { pin_type: ["BoxLed3", "BoxLed4"].sample, pin_id: 0 } args: { pin_type: ["BoxLed3", "BoxLed4"].sample, pin_id: 0 },
} },
} },
} },
] ]
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
expected = \ expected =
CeleryScriptSettingsBag::NO_PIN_ID % CeleryScriptSettingsBag::BoxLed.name CeleryScriptSettingsBag::NO_PIN_ID % CeleryScriptSettingsBag::BoxLed.name
expect(chk.error.message).to eq(expected) expect(chk.error.message).to eq(expected)
end end
it "catches bad `axis` nodes" do it "catches bad `axis` nodes" do
t = \ t =
CeleryScript::AstNode.new({kind: "home", args: { speed: 100, axis: "?" }}) CeleryScript::AstNode.new({ kind: "home", args: { speed: 100, axis: "?" } })
chk = CeleryScript::Checker.new(t, corpus, device) chk = CeleryScript::Checker.new(t, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
expect(chk.error.message).to include("not a valid axis") expect(chk.error.message).to include("not a valid axis")
end end
it "catches bad `package` nodes" do it "catches bad `package` nodes" do
t = \ t = CeleryScript::AstNode.new({ kind: "factory_reset", args: { package: "?" } })
CeleryScript::AstNode.new({ kind: "factory_reset", args: { package: "?" }}) chk = CeleryScript::Checker.new(t, corpus, device)
chk = CeleryScript::Checker.new(t, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
expect(chk.error.message).to include("not a valid package") expect(chk.error.message).to include("not a valid package")
end end
@ -225,7 +220,7 @@ describe CeleryScript::Checker do
version: 20180209, version: 20180209,
locals: { locals: {
kind: "scope_declaration", kind: "scope_declaration",
:args=>{}, :args => {},
body: [ body: [
{ {
kind: "parameter_declaration", kind: "parameter_declaration",
@ -233,11 +228,12 @@ describe CeleryScript::Checker do
label: "parent", label: "parent",
default_value: { default_value: {
kind: "coordinate", kind: "coordinate",
args: { x: 0, y: 0, z: 0 } } args: { x: 0, y: 0, z: 0 },
} },
} },
] },
} ],
},
}, },
body: [ body: [
{ {
@ -245,13 +241,13 @@ describe CeleryScript::Checker do
args: { args: {
speed: 100, speed: 100,
location: { kind: "identifier", args: { label: "parent" } }, location: { kind: "identifier", args: { label: "parent" } },
offset: { kind: "coordinate", args: { x: 0, y: 0, z: 0} } offset: { kind: "coordinate", args: { x: 0, y: 0, z: 0 } },
} },
} },
] ],
} }
tree = CeleryScript::AstNode.new(ast) tree = CeleryScript::AstNode.new(ast)
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be true expect(chk.valid?).to be true
end end
@ -262,7 +258,7 @@ describe CeleryScript::Checker do
version: 20180209, version: 20180209,
locals: { locals: {
kind: "scope_declaration", kind: "scope_declaration",
:args=>{}, :args => {},
body: [ body: [
{ {
kind: "parameter_declaration", kind: "parameter_declaration",
@ -270,12 +266,12 @@ describe CeleryScript::Checker do
label: "parent", label: "parent",
default_value: { default_value: {
kind: "nothing", kind: "nothing",
args: { } args: {},
} },
} },
} },
] ],
} },
}, },
body: [ body: [
{ {
@ -283,13 +279,13 @@ describe CeleryScript::Checker do
args: { args: {
speed: 100, speed: 100,
location: { kind: "identifier", args: { label: "parent" } }, location: { kind: "identifier", args: { label: "parent" } },
offset: { kind: "coordinate", args: { x: 0, y: 0, z: 0} } offset: { kind: "coordinate", args: { x: 0, y: 0, z: 0 } },
} },
} },
] ],
} }
tree = CeleryScript::AstNode.new(ast) tree = CeleryScript::AstNode.new(ast)
chk = CeleryScript::Checker.new(tree, corpus, device) chk = CeleryScript::Checker.new(tree, corpus, device)
expect(chk.valid?).to be false expect(chk.valid?).to be false
message = "must provide a value for all parameters" message = "must provide a value for all parameters"
expect(chk.error.message).to include(message) expect(chk.error.message).to include(message)