Skip to content
Merged
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
22 changes: 11 additions & 11 deletions cmd/sysml/convert_branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@ func TestConvertReadsABranchAsNotationAndTurtle(t *testing.T) {
func TestConvertReadsABranchIntoAFileAndRecordsTheHead(t *testing.T) {
binary := buildCLI(t)
stack := newFakeStack(t, liveGraph(t, syncedModel))
out_path := filepath.Join(t.TempDir(), "out.sysml")
outPath := filepath.Join(t.TempDir(), "out.sysml")

out, code := exitCode(t, branchCommand(stack, binary, stack.server.URL+"/projects/proj-1/branches/main", "-convert", "sysml", "-o", out_path))
out, code := exitCode(t, branchCommand(stack, binary, stack.server.URL+"/projects/proj-1/branches/main", "-convert", "sysml", "-o", outPath))
if code != 0 {
t.Fatalf("read a branch to a file: exit %d:\n%s", code, out)
}
written, err := os.ReadFile(out_path)
written, err := os.ReadFile(outPath)
if err != nil || !strings.Contains(string(written), "part def Vehicle") {
t.Fatalf("the output file: %v\n%s", err, written)
}
state, err := os.ReadFile(out_path + ".sync.json")
state, err := os.ReadFile(outPath + ".sync.json")
if err != nil || !strings.Contains(string(state), `"lastSeenCommit": "commit-0"`) || !strings.Contains(string(state), `"projectId": "proj-1"`) {
t.Fatalf("sync state after a branch read: %v\n%s", err, state)
}
Expand Down Expand Up @@ -250,13 +250,13 @@ func TestConvertReadRefusesOutputOverTheSyncState(t *testing.T) {
binary := buildCLI(t)
stack := newFakeStack(t, liveGraph(t, syncedModel))
dir := t.TempDir()
out_path := writeModel(t, dir, "saved.sysml", "sentinel")
outPath := writeModel(t, dir, "saved.sysml", "sentinel")

out, code := exitCode(t, branchCommand(stack, binary, "flexo://proj-1/main", "-convert", "sysml", "-o", out_path, "-sync-state", out_path))
out, code := exitCode(t, branchCommand(stack, binary, "flexo://proj-1/main", "-convert", "sysml", "-o", outPath, "-sync-state", outPath))
if code != 2 || !strings.Contains(out, "-o and -sync-state both name") {
t.Fatalf("-o over the sync state: exit %d:\n%s", code, out)
}
if content, _ := os.ReadFile(out_path); string(content) != "sentinel" {
if content, _ := os.ReadFile(outPath); string(content) != "sentinel" {
t.Errorf("the refused read still replaced the file")
}
}
Expand All @@ -266,16 +266,16 @@ func TestConvertReadRefusesAStatePinnedElsewhereBeforeWriting(t *testing.T) {
stack := newFakeStack(t, liveGraph(t, syncedModel))
dir := t.TempDir()
state := writeModel(t, dir, "s.sync.json", `{"org":"other","projectId":"proj-1","branch":"main"}`)
out_path := filepath.Join(dir, "out.sysml")
outPath := filepath.Join(dir, "out.sysml")

cmd := branchCommand(stack, binary, "flexo://proj-1/main", "-convert", "sysml", "-o", out_path, "-sync-state", state)
cmd := branchCommand(stack, binary, "flexo://proj-1/main", "-convert", "sysml", "-o", outPath, "-sync-state", state)
cmd.Env = append(cmd.Env, flexo.EnvOrg+"=acme")
out, code := exitCode(t, cmd)
if code != 2 || !strings.Contains(out, "org other") {
t.Fatalf("a state pinned to another org: exit %d:\n%s", code, out)
}
if _, err := os.Stat(out_path); !os.IsNotExist(err) {
t.Errorf("the refused read still wrote %s", out_path)
if _, err := os.Stat(outPath); !os.IsNotExist(err) {
t.Errorf("the refused read still wrote %s", outPath)
}
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/sysml/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ func TestRenderFilenameFitsAPathComponent(t *testing.T) {
if got != renderFilename(long+"first", view.FormDot, false) {
t.Errorf("renderFilename(long) is not deterministic")
}
if other := renderFilename(long+"second", view.FormDot, false); other == got {
if renderFilename(long+"second", view.FormDot, false) == got {
t.Errorf("two long names that differ only past the cut share %q", got)
}
a := strings.Repeat("a", 230)
Expand Down
7 changes: 4 additions & 3 deletions cmd/sysml/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

// The help-text placeholders and check flag names the help repeats.
const (
callArg = "<call>"
nameArg = "<name>"
fileArg = "<file>"
featureArg = "<feature>"
Expand Down Expand Up @@ -658,9 +659,9 @@ func optionGroups() []usage.OptionGroup {
usage.Opt("constraint", nameArg),
usage.Opt("requirement", nameArg),
usage.Opt("satisfy", "[=<name>]"),
usage.Opt("calc", "<call>"),
usage.Opt("analysis", "<call>"),
usage.Opt("record-run", "<call>"),
usage.Opt("calc", callArg),
usage.Opt("analysis", callArg),
usage.Opt("record-run", callArg),
usage.Opt("record-into", "<package>"),
usage.Opt("run-query", "<query>"),
usage.Opt("instantiate", nameArg),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.openmbee.opensysml.cameo.tools;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
Expand All @@ -28,7 +28,7 @@ void stagesAllAssetsWithGoodDigests() throws IOException, InterruptedException {
Files.writeString(pin, json);
Map<String, String> written =
BinaryStager.stage("v1.2.3", Files.createTempDirectory("staged"), base(server), pin);
assertTrue(written.size() == 5);
assertEquals(5, written.size());
} finally {
server.stop(0);
}
Expand All @@ -42,17 +42,19 @@ void rejectsTamperedAsset() throws IOException, InterruptedException {
try {
Path pin = Files.createTempFile("digests", ".json");
Files.writeString(pin, json);
assertThrows(Exception.class, () -> BinaryStager.stage("v1.2.3", Files.createTempDirectory("staged"), base(server), pin));
Path staged = Files.createTempDirectory("staged");
assertThrows(Exception.class, () -> BinaryStager.stage("v1.2.3", staged, base(server), pin));
} finally {
server.stop(0);
}
}

@Test
void rejectsUnpinnedVersion() throws IOException, InterruptedException {
void rejectsUnpinnedVersion() throws IOException {
Path pin = Files.createTempFile("digests", ".json");
Files.writeString(pin, "{\"v1.2.3\":{}}");
assertThrows(IllegalArgumentException.class, () -> BinaryStager.stage("v9.9.9", Files.createTempDirectory("staged"), "http://127.0.0.1", pin));
Path staged = Files.createTempDirectory("staged");
assertThrows(IllegalArgumentException.class, () -> BinaryStager.stage("v9.9.9", staged, "http://127.0.0.1", pin));
}

private static HttpServer server(byte[] payload) throws IOException {
Expand Down
4 changes: 2 additions & 2 deletions editors/vscode/src/webview/autolayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ function reconcile(
if (node.height !== undefined) {
geometry.height = node.height;
}
for (const [index, points] of [...routes]) {
for (const [index, points] of routes) {
const edge = result.edges![index];
const from = inside.has(edge.from);
const to = inside.has(edge.to);
Expand Down Expand Up @@ -242,7 +242,7 @@ function reconcile(
geometry.width = right - left;
geometry.height = bottom - top;
// The box moved, so routes anchored on its old border are dropped; they are drawn straight.
for (const [index] of [...routes]) {
for (const [index] of routes) {
const edge = result.edges![index];
if (edge.from === node.id || edge.to === node.id) {
routes.delete(index);
Expand Down
42 changes: 25 additions & 17 deletions internal/exec/analysis/record/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ const (
kindQuantity
)

const (
scalarValuesString = "ScalarValues::String"
scalarValuesReal = "ScalarValues::Real"
scalarValuesInteger = "ScalarValues::Integer"
scalarValuesBoolean = "ScalarValues::Boolean"
scalarValuesScalarValue = "ScalarValues::ScalarValue"
)

// shape is how a value is recorded: its feature kind, the literal spelling,
// and — for a quantity — the unit text its companion feature records.
type shape struct {
Expand Down Expand Up @@ -226,12 +234,12 @@ func classify(v runtime.Value, r *Run) shape {
}
// A constant without a literal spelling, Infinity included, is
// recorded as a string of its text.
return shape{kind: kindString, typ: "ScalarValues::String", literal: source.StringText(semantics.FormatConst(v.Const))}
return shape{kind: kindString, typ: scalarValuesString, literal: source.StringText(semantics.FormatConst(v.Const))}
case runtime.ValString:
return shape{kind: kindString, typ: "ScalarValues::String", literal: source.StringText(v.Str())}
return shape{kind: kindString, typ: scalarValuesString, literal: source.StringText(v.Str())}
case runtime.ValQuantity:
q := v.Quantity()
return shape{kind: kindQuantity, typ: "ScalarValues::Real", literal: semantics.FormatConst(q.Num), unit: q.Unit.String()}
return shape{kind: kindQuantity, typ: scalarValuesReal, literal: semantics.FormatConst(q.Num), unit: q.Unit.String()}
case runtime.ValInstance, runtime.ValVariant:
if r.Spell.ObjectUsage != nil {
if usage := r.Spell.ObjectUsage(v); usage != "" {
Expand All @@ -241,7 +249,7 @@ func classify(v runtime.Value, r *Run) shape {
}
// Everything else — a structured value, or an object naming no usage — is
// recorded by its text.
return shape{kind: kindString, typ: "ScalarValues::String", literal: source.StringText(spellText(v, r))}
return shape{kind: kindString, typ: scalarValuesString, literal: source.StringText(spellText(v, r))}
}

// constScalar is the feature kind and ScalarValues type a scalar literal's
Expand All @@ -250,11 +258,11 @@ func classify(v runtime.Value, r *Run) shape {
func constScalar(k semantics.ValueKind) (valueKind, string, bool) {
switch k {
case semantics.ValInt:
return kindInteger, "ScalarValues::Integer", true
return kindInteger, scalarValuesInteger, true
case semantics.ValReal:
return kindReal, "ScalarValues::Real", true
return kindReal, scalarValuesReal, true
case semantics.ValBool:
return kindBoolean, "ScalarValues::Boolean", true
return kindBoolean, scalarValuesBoolean, true
}
return 0, "", false
}
Expand Down Expand Up @@ -388,7 +396,7 @@ func buildFeatures(req *Request) ([]feature, error) {
// definition: either way the member settles to Real, an Integer
// literal remaining valid under it.
if numericPair(cur.typ, sh.typ) {
cur = shape{kind: kindReal, typ: "ScalarValues::Real"}
cur = shape{kind: kindReal, typ: scalarValuesReal}
shapes[m.name] = cur
continue
}
Expand All @@ -410,8 +418,8 @@ func buildFeatures(req *Request) ([]feature, error) {
case c.kind == kindQuantity && (o.kind == kindInteger || o.kind == kindReal):
shapes[owner] = c
case numericPair(o.typ, c.typ):
shapes[owner] = shape{kind: kindReal, typ: "ScalarValues::Real"}
shapes[companion] = shape{kind: kindReal, typ: "ScalarValues::Real"}
shapes[owner] = shape{kind: kindReal, typ: scalarValuesReal}
shapes[companion] = shape{kind: kindReal, typ: scalarValuesReal}
default:
f := feature{name: owner}
applyShape(&f, o)
Expand All @@ -437,7 +445,7 @@ func buildFeatures(req *Request) ([]feature, error) {
applyShape(&f, shapes[name])
feats = append(feats, f)
if shapes[name].kind == kindQuantity {
feats = append(feats, feature{name: name + "Unit", typ: "ScalarValues::String", unitOf: name})
feats = append(feats, feature{name: name + "Unit", typ: scalarValuesString, unitOf: name})
}
}
return feats, nil
Expand All @@ -446,16 +454,16 @@ func buildFeatures(req *Request) ([]feature, error) {
// numericPair reports whether the types are Integer and Real in either order:
// one numeric family for the record definition, settling to Real.
func numericPair(a, b string) bool {
return (a == "ScalarValues::Integer" && b == "ScalarValues::Real") ||
(a == "ScalarValues::Real" && b == "ScalarValues::Integer")
return (a == scalarValuesInteger && b == scalarValuesReal) ||
(a == scalarValuesReal && b == scalarValuesInteger)
}

// applyShape gives a feature the declared shape a value's first supply asks for.
func applyShape(f *feature, sh shape) {
f.ref = sh.kind == kindRef
switch sh.kind {
case kindUnset:
f.typ = "ScalarValues::ScalarValue"
f.typ = scalarValuesScalarValue
case kindRef:
f.typ = ""
default:
Expand All @@ -474,7 +482,7 @@ func compatible(f *feature, sh shape) error {
if f.ref || sh.kind == kindRef {
return nil
}
if f.typ == "ScalarValues::ScalarValue" {
if f.typ == scalarValuesScalarValue {
// The first supply was unset; a settled value gives the member its type.
f.typ = source.QualifiedNameText(sh.typ)
return nil
Expand Down Expand Up @@ -596,11 +604,11 @@ func checkExisting(req *Request, feats []feature, defName string) error {
return fmt.Errorf("record definition %s declares %s as %s but the run values need %s; record into another package with `into`", def, f.name, kind, want)
}
if !f.ref && f.typ != "" && decl.TypeFQN != "" && decl.TypeFQN != f.typ &&
f.typ != "ScalarValues::ScalarValue" && decl.TypeFQN != "ScalarValues::ScalarValue" {
f.typ != scalarValuesScalarValue && decl.TypeFQN != scalarValuesScalarValue {
// An Integer literal is valid under a declared Real; the
// reverse would widen a definition the model owns, so it stays
// refused.
if decl.TypeFQN == "ScalarValues::Real" && f.typ == "ScalarValues::Integer" {
if decl.TypeFQN == scalarValuesReal && f.typ == scalarValuesInteger {
continue
}
return fmt.Errorf("record definition %s declares %s : %s but the run values need %s : %s; record into another package with `into`", def, f.name, decl.TypeFQN, f.name, f.typ)
Expand Down
Loading
Loading