Updates to corpus + generator.
parent
8b79fdd866
commit
9399ad7f27
|
@ -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)
|
||||||
|
|
147
latest_corpus.rb
147
latest_corpus.rb
|
@ -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!
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue