go/workspace: implement EvalHscloudNix

This allows us to access hscloud nix 'facts' from Go.

Change-Id: Ic8fc3350a7d073947c44529fcae0bbb8627421aa
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1508
Reviewed-by: q3k <q3k@hackerspace.pl>
diff --git a/go/workspace/nix_test.go b/go/workspace/nix_test.go
new file mode 100644
index 0000000..acb6d99
--- /dev/null
+++ b/go/workspace/nix_test.go
@@ -0,0 +1,90 @@
+package workspace
+
+import (
+	"context"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestCheckNixPath(t *testing.T) {
+	for _, te := range []struct {
+		in   string
+		okay bool
+	}{
+		{"foo", true},
+		{"foo.bar.baz", true},
+		{"foo.bar.baz.", false},
+		{"foo.bar.baz..", false},
+		{".foo.bar.baz", false},
+		{"..foo.bar.baz", false},
+		{"foo..bar.baz", false},
+		{".", false},
+		{"", false},
+
+		{"ops.machines.\"test.example.com\".config", true},
+		{"ops.machines.\"test.example.com.config", false},
+		{"ops.machines.\"test.example.com\"bar.config", false},
+		{"ops.machines.bar\"test.example.com\".config", false},
+		{"\"test.example.com\"bar", false},
+		{"test.example.com\"", false},
+
+		{"foo--.__bar.b-a-z---", true},
+		{"foo.0bar", false},
+		{"foo.-bar", false},
+
+		{"test\\.test", false},
+		{"test test", false},
+	} {
+		err := checkNixPath(te.in)
+		if te.okay && err != nil {
+			t.Errorf("%q: expected okay, got %v", te.in, err)
+		}
+		if !te.okay && err == nil {
+			t.Errorf("%q: expected error", te.in)
+		}
+	}
+}
+
+// TestEvalHscloud nix exercises EvalHscloudNix against
+// //go/workspace/exports.nix.
+func TestEvalHscloudNix(t *testing.T) {
+	ctx, ctxC := context.WithCancel(context.Background())
+	defer ctxC()
+
+	{
+		var got []string
+		if err := EvalHscloudNix(ctx, &got, "go.workspace.exports.someArray"); err != nil {
+			t.Errorf("Accessing someArray failed: %v", err)
+		} else {
+			want := []string{"hello", "there"}
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("someArray diff:\n%s", diff)
+			}
+		}
+	}
+
+	{
+		type barS struct {
+			Baz int64 `json:"baz"`
+		}
+		type gotS struct {
+			Foo string `json:"foo"`
+			Bar barS   `json:"bar"`
+		}
+		var got gotS
+		if err := EvalHscloudNix(ctx, &got, "go.workspace.exports.someAttrset"); err != nil {
+			t.Errorf("Accessing someAttrset failed: %v", err)
+		} else {
+			want := gotS{
+				Foo: "foo",
+				Bar: barS{
+					Baz: 42,
+				},
+			}
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Errorf("someAttrset diff:\n%s", diff)
+			}
+		}
+	}
+}