1// Copyright 2016 The OPA Authors.  All rights reserved.
2// Use of this source code is governed by an Apache2
3// license that can be found in the LICENSE file.
4
5package repl
6
7import (
8	"bytes"
9	"context"
10	"encoding/json"
11	"fmt"
12	"io"
13	"io/ioutil"
14	"os"
15	"path/filepath"
16	"reflect"
17	"sort"
18	"strings"
19	"testing"
20
21	"github.com/open-policy-agent/opa/ast"
22	"github.com/open-policy-agent/opa/internal/presentation"
23	"github.com/open-policy-agent/opa/storage"
24	"github.com/open-policy-agent/opa/storage/inmem"
25	"github.com/open-policy-agent/opa/util"
26)
27
28func TestFunction(t *testing.T) {
29	store := newTestStore()
30	ctx := context.Background()
31	txn := storage.NewTransactionOrDie(ctx, store, storage.WriteParams)
32
33	mod1 := []byte(`package a.b.c
34
35foo(x) = y {
36	split(x, ".", y)
37}
38
39bar([x, y]) = z {
40	trim(x, y, z)
41}
42`)
43
44	mod2 := []byte(`package a.b.d
45
46baz(_) = y {
47	data.a.b.c.foo("barfoobar.bar", x)
48	data.a.b.c.bar(x, y)
49}`)
50
51	if err := store.UpsertPolicy(ctx, txn, "mod1", mod1); err != nil {
52		panic(err)
53	}
54
55	if err := store.UpsertPolicy(ctx, txn, "mod2", mod2); err != nil {
56		panic(err)
57	}
58
59	if err := store.Commit(ctx, txn); err != nil {
60		panic(err)
61	}
62
63	var buf bytes.Buffer
64	repl := newRepl(store, &buf)
65	repl.OneShot(ctx, "json")
66	repl.OneShot(ctx, "data.a.b.d.baz(null, x)")
67	exp := util.MustUnmarshalJSON([]byte(`{"result": [{"expressions": [{"text":"data.a.b.d.baz(null, x)", "value": true, "location": {"row": 1, "col": 1}}], "bindings": {"x": "foo"}}]}`))
68	result := util.MustUnmarshalJSON(buf.Bytes())
69	if !reflect.DeepEqual(exp, result) {
70		t.Fatalf("expected data.a.b.d.baz(x) to be %v, got %v", exp, result)
71	}
72
73	err := repl.OneShot(ctx, "p(x) = y { y = x+4 }")
74	if err != nil {
75		t.Fatalf("failed to compile repl function: %v", err)
76	}
77
78	buf.Reset()
79	repl.OneShot(ctx, "data.repl.p(5, y)")
80	exp = util.MustUnmarshalJSON([]byte(`{
81		"result": [
82			{
83				"expressions": [
84					{
85						"text": "data.repl.p(5, y)",
86						"value": true,
87						"location": {
88							"col": 1,
89							"row": 1
90						}
91					}
92				],
93				"bindings": {
94					"y": 9
95				}
96			}
97		]
98	}`))
99	result = util.MustUnmarshalJSON(buf.Bytes())
100	if !reflect.DeepEqual(exp, result) {
101		t.Fatalf("expected datrepl.p(x) to be %v, got %v", exp, result)
102	}
103
104	repl.OneShot(ctx, "f(1, x) = y { y = x }")
105	repl.OneShot(ctx, "f(2, x) = y { y = x*2 }")
106
107	buf.Reset()
108	repl.OneShot(ctx, "data.repl.f(1, 2, y)")
109	exp = util.MustUnmarshalJSON([]byte(`{
110		"result": [
111			{
112				"expressions": [
113					{
114						"text": "data.repl.f(1, 2, y)",
115						"location": {
116							"col": 1,
117							"row": 1
118						},
119						"value": true
120					}
121				],
122				"bindings": {
123					"y": 2
124				}
125			}
126		]
127	}`))
128	result = util.MustUnmarshalJSON(buf.Bytes())
129	if !reflect.DeepEqual(exp, result) {
130		t.Fatalf("expected data.repl.f(1, 2, y) to be %v, got %v", exp, result)
131	}
132	buf.Reset()
133	repl.OneShot(ctx, "data.repl.f(2, 2, y)")
134	exp = util.MustUnmarshalJSON([]byte(`{
135		"result": [
136			{
137				"expressions": [
138					{
139						"text": "data.repl.f(2, 2, y)",
140						"location": {
141							"col": 1,
142							"row": 1
143						},
144						"value": true
145					}
146				],
147				"bindings": {
148					"y": 4
149				}
150			}
151		]
152	}`))
153	result = util.MustUnmarshalJSON(buf.Bytes())
154	if !reflect.DeepEqual(exp, result) {
155		t.Fatalf("expected data.repl.f(2, 2, y) to be %v, got %v", exp, result)
156	}
157}
158
159func TestComplete(t *testing.T) {
160	ctx := context.Background()
161	store := newTestStore()
162	txn := storage.NewTransactionOrDie(ctx, store, storage.WriteParams)
163
164	mod1 := []byte(`package a.b.c
165
166p = 1 { true }
167q = 2 { true }
168q = 3 { false }`)
169
170	mod2 := []byte(`package a.b.d
171
172r = 3 { true }`)
173
174	if err := store.UpsertPolicy(ctx, txn, "mod1", mod1); err != nil {
175		panic(err)
176	}
177
178	if err := store.UpsertPolicy(ctx, txn, "mod2", mod2); err != nil {
179		panic(err)
180	}
181
182	if err := store.Commit(ctx, txn); err != nil {
183		panic(err)
184	}
185
186	var buf bytes.Buffer
187	repl := newRepl(store, &buf)
188	repl.OneShot(ctx, "s = 4")
189	buf.Reset()
190
191	result := repl.complete("")
192	expected := []string{
193		"data.a.b.c.p",
194		"data.a.b.c.q",
195		"data.a.b.d.r",
196		"data.repl.s",
197	}
198
199	sort.Strings(result)
200	sort.Strings(expected)
201
202	if !reflect.DeepEqual(result, expected) {
203		t.Fatalf("Expected %v but got: %v", expected, result)
204	}
205
206	result = repl.complete("data.a.b")
207	expected = []string{
208		"data.a.b.c.p",
209		"data.a.b.c.q",
210		"data.a.b.d.r",
211	}
212
213	sort.Strings(result)
214	sort.Strings(expected)
215
216	if !reflect.DeepEqual(result, expected) {
217		t.Fatalf("Expected %v but got: %v", expected, result)
218	}
219
220	result = repl.complete("data.a.b.c.p[x]")
221	expected = []string{}
222
223	if !reflect.DeepEqual(result, expected) {
224		t.Fatalf("Expected %v but got: %v", expected, result)
225	}
226
227	repl.OneShot(ctx, "import data.a.b.c.p as xyz")
228	repl.OneShot(ctx, "import data.a.b.d")
229
230	result = repl.complete("x")
231	expected = []string{
232		"xyz",
233	}
234
235	if !reflect.DeepEqual(result, expected) {
236		t.Fatalf("Expected %v but got: %v", expected, result)
237	}
238}
239
240func TestDump(t *testing.T) {
241	ctx := context.Background()
242	input := `{"a": [1,2,3,4]}`
243	var data map[string]interface{}
244	err := util.UnmarshalJSON([]byte(input), &data)
245	if err != nil {
246		panic(err)
247	}
248	store := inmem.NewFromObject(data)
249	var buffer bytes.Buffer
250	repl := newRepl(store, &buffer)
251	repl.OneShot(ctx, "dump")
252	expectOutput(t, buffer.String(), "{\"a\":[1,2,3,4]}\n")
253}
254
255func TestDumpPath(t *testing.T) {
256	ctx := context.Background()
257	input := `{"a": [1,2,3,4]}`
258	var data map[string]interface{}
259	err := util.UnmarshalJSON([]byte(input), &data)
260	if err != nil {
261		panic(err)
262	}
263	store := inmem.NewFromObject(data)
264	var buffer bytes.Buffer
265	repl := newRepl(store, &buffer)
266
267	dir, err := ioutil.TempDir("", "dump-path-test")
268	if err != nil {
269		t.Fatal(err)
270	}
271
272	defer os.RemoveAll(dir)
273	file := filepath.Join(dir, "tmpfile")
274	repl.OneShot(ctx, fmt.Sprintf("dump %s", file))
275
276	if buffer.String() != "" {
277		t.Errorf("Expected no output but got: %v", buffer.String())
278	}
279
280	bs, err := ioutil.ReadFile(file)
281	if err != nil {
282		t.Fatalf("Expected file read to succeed but got: %v", err)
283	}
284
285	var result map[string]interface{}
286	if err := util.UnmarshalJSON(bs, &result); err != nil {
287		t.Fatalf("Expected json unmarshal to succeed but got: %v", err)
288	}
289
290	if !reflect.DeepEqual(data, result) {
291		t.Fatalf("Expected dumped json to equal %v but got: %v", data, result)
292	}
293}
294
295func TestHelp(t *testing.T) {
296	topics["deadbeef"] = topicDesc{
297		fn: func(w io.Writer) error {
298			fmt.Fprintln(w, "blah blah blah")
299			return nil
300		},
301	}
302
303	ctx := context.Background()
304	store := inmem.New()
305	var buffer bytes.Buffer
306	repl := newRepl(store, &buffer)
307	repl.OneShot(ctx, "help deadbeef")
308
309	expected := "blah blah blah\n"
310
311	if buffer.String() != expected {
312		t.Fatalf("Unexpected output from help topic: %v", buffer.String())
313	}
314}
315
316func TestShowDebug(t *testing.T) {
317	ctx := context.Background()
318	store := inmem.New()
319	var buffer bytes.Buffer
320	repl := newRepl(store, &buffer)
321	repl.OneShot(ctx, "show debug")
322
323	var result replDebugState
324
325	if err := util.Unmarshal(buffer.Bytes(), &result); err != nil {
326		t.Fatal(err)
327	}
328
329	var exp replDebugState
330	exp.Explain = explainOff
331
332	if !reflect.DeepEqual(result, exp) {
333		t.Fatalf("Expected %+v but got %+v", exp, result)
334	}
335
336	buffer.Reset()
337
338	repl.OneShot(ctx, "trace")
339	repl.OneShot(ctx, "metrics")
340	repl.OneShot(ctx, "instrument")
341	repl.OneShot(ctx, "profile")
342	repl.OneShot(ctx, "show debug")
343
344	exp.Explain = explainFull
345	exp.Metrics = true
346	exp.Instrument = true
347	exp.Profile = true
348
349	if err := util.Unmarshal(buffer.Bytes(), &result); err != nil {
350		t.Fatal(err)
351	}
352
353	if !reflect.DeepEqual(result, exp) {
354		t.Fatalf("Expected %+v but got %+v", exp, result)
355	}
356}
357
358func TestShow(t *testing.T) {
359	ctx := context.Background()
360	store := inmem.New()
361	var buffer bytes.Buffer
362	repl := newRepl(store, &buffer)
363
364	repl.OneShot(ctx, `package repl_test`)
365	repl.OneShot(ctx, "show")
366	assertREPLText(t, buffer, "package repl_test\n")
367	buffer.Reset()
368
369	repl.OneShot(ctx, "import input.xyz")
370	repl.OneShot(ctx, "show")
371
372	expected := `package repl_test
373
374import input.xyz` + "\n"
375	assertREPLText(t, buffer, expected)
376	buffer.Reset()
377
378	repl.OneShot(ctx, "import data.foo as bar")
379	repl.OneShot(ctx, "show")
380
381	expected = `package repl_test
382
383import data.foo as bar
384import input.xyz` + "\n"
385	assertREPLText(t, buffer, expected)
386	buffer.Reset()
387
388	repl.OneShot(ctx, `p[1] { true }`)
389	buffer.Reset()
390	repl.OneShot(ctx, `p[2] { true }`)
391	buffer.Reset()
392	repl.OneShot(ctx, "show")
393
394	expected = `package repl_test
395
396import data.foo as bar
397import input.xyz
398
399p[1]
400
401p[2]` + "\n"
402	assertREPLText(t, buffer, expected)
403	buffer.Reset()
404
405	repl.OneShot(ctx, "package abc")
406	repl.OneShot(ctx, "show")
407
408	assertREPLText(t, buffer, "package abc\n")
409	buffer.Reset()
410
411	repl.OneShot(ctx, "package repl_test")
412	repl.OneShot(ctx, "show")
413
414	assertREPLText(t, buffer, expected)
415	buffer.Reset()
416}
417
418func TestTypes(t *testing.T) {
419	ctx := context.Background()
420	store := inmem.New()
421	var buffer bytes.Buffer
422	repl := newRepl(store, &buffer)
423
424	repl.OneShot(ctx, "types")
425	repl.OneShot(ctx, `p[x] = y { x := "a"; y := 1 }`)
426	repl.OneShot(ctx, `p[x]`)
427
428	output := strings.TrimSpace(buffer.String())
429
430	exp := []string{
431		"# data.repl.p[x]: number",
432		"# x: string",
433	}
434
435	for i := range exp {
436		if !strings.Contains(output, exp[i]) {
437			t.Fatalf("Expected output to contain %q but got: %v", exp[i], output)
438		}
439	}
440
441}
442
443func TestUnknown(t *testing.T) {
444	ctx := context.Background()
445	store := inmem.New()
446	var buffer bytes.Buffer
447	repl := newRepl(store, &buffer)
448
449	repl.OneShot(ctx, "xs = [1,2,3]")
450	buffer.Reset()
451
452	err := repl.OneShot(ctx, "unknown input")
453	if err != nil {
454		t.Fatal("Unexpected command error:", err)
455	}
456
457	repl.OneShot(ctx, "data.repl.xs[i] = x; input.x = x")
458
459	output := strings.TrimSpace(buffer.String())
460	expected := strings.TrimSpace(`
461+---------+-------------+
462| Query 1 | input.x = 1 |
463|         | i = 0       |
464|         | x = 1       |
465+---------+-------------+
466| Query 2 | input.x = 2 |
467|         | i = 1       |
468|         | x = 2       |
469+---------+-------------+
470| Query 3 | input.x = 3 |
471|         | i = 2       |
472|         | x = 3       |
473+---------+-------------+
474`)
475
476	if output != expected {
477		t.Fatalf("Unexpected output. Expected:\n\n%v\n\nGot:\n\n%v", expected, output)
478	}
479}
480func TestUnknownMetrics(t *testing.T) {
481	ctx := context.Background()
482	store := inmem.New()
483	var buffer bytes.Buffer
484	repl := newRepl(store, &buffer)
485
486	repl.OneShot(ctx, "xs = [1,2,3]")
487	buffer.Reset()
488
489	err := repl.OneShot(ctx, "unknown input")
490	if err != nil {
491		t.Fatal("Unexpected command error:", err)
492	}
493
494	repl.OneShot(ctx, "metrics")
495
496	repl.OneShot(ctx, "data.repl.xs[i] = x; input.x = x")
497
498	output := strings.TrimSpace(buffer.String())
499	expected := strings.TrimSpace(`
500+---------+-------------+
501| Query 1 | input.x = 1 |
502|         | i = 0       |
503|         | x = 1       |
504+---------+-------------+
505| Query 2 | input.x = 2 |
506|         | i = 1       |
507|         | x = 2       |
508+---------+-------------+
509| Query 3 | input.x = 3 |
510|         | i = 2       |
511|         | x = 3       |
512+---------+-------------+
513`)
514
515	if !strings.HasPrefix(output, expected) {
516		t.Fatalf("Unexpected partial eval results. Expected:\n\n%v\n\nGot:\n\n%v", expected, output)
517	}
518
519	if !strings.Contains(output, "timer_rego_partial_eval_ns") {
520		t.Fatal("Expected timer_rego_partial_eval_ns but got:\n\n", output)
521	}
522}
523
524func TestUnknownJSON(t *testing.T) {
525	ctx := context.Background()
526	store := inmem.New()
527	var buffer bytes.Buffer
528	repl := newRepl(store, &buffer)
529
530	repl.OneShot(ctx, "xs = [1,2,3]")
531	buffer.Reset()
532
533	err := repl.OneShot(ctx, "unknown input")
534	if err != nil {
535		t.Fatal("Unexpected command error:", err)
536	}
537
538	repl.OneShot(ctx, "json")
539	repl.OneShot(ctx, "data.repl.xs[i] = x; input.x = x")
540
541	var result presentation.Output
542
543	if err := json.NewDecoder(&buffer).Decode(&result); err != nil {
544		t.Fatal(err)
545	}
546
547	if len(result.Partial.Queries) != 3 {
548		t.Fatalf("Expected exactly 3 queries in partial evaluation output but got: %v", result)
549	}
550}
551
552func TestUnknownInvalid(t *testing.T) {
553	ctx := context.Background()
554	store := inmem.New()
555	var buffer bytes.Buffer
556	repl := newRepl(store, &buffer)
557
558	err := repl.OneShot(ctx, "unknown x-1")
559	if err == nil || !strings.Contains(err.Error(), "usage: unknown <input/data reference>") {
560		t.Fatal("expected error from setting bad unknown but got:", err)
561	}
562
563	// Ensure that partial evaluation has not been enabled.
564	buffer.Reset()
565	repl.OneShot(ctx, "1+2")
566	result := strings.TrimSpace(buffer.String())
567	if result != "3" {
568		t.Fatal("want true but got:", result)
569	}
570}
571
572func TestUnset(t *testing.T) {
573	ctx := context.Background()
574	store := inmem.New()
575	var buffer bytes.Buffer
576	repl := newRepl(store, &buffer)
577
578	var err error
579
580	repl.OneShot(ctx, "magic = 23")
581	repl.OneShot(ctx, "p = 3.14")
582	repl.OneShot(ctx, "unset p")
583
584	err = repl.OneShot(ctx, "p")
585
586	if _, ok := err.(ast.Errors); !ok {
587		t.Fatalf("Expected AST error but got: %v", err)
588	}
589
590	buffer.Reset()
591	repl.OneShot(ctx, "p = 3.14")
592	repl.OneShot(ctx, `p = 3 { false }`)
593	repl.OneShot(ctx, "unset p")
594
595	err = repl.OneShot(ctx, "p")
596	if _, ok := err.(ast.Errors); !ok {
597		t.Fatalf("Expected AST error but got err: %v, output: %v", err, buffer.String())
598	}
599
600	if err := repl.OneShot(ctx, "unset "); err == nil {
601		t.Fatalf("Expected unset error for bad syntax but got: %v", buffer.String())
602	}
603
604	if err := repl.OneShot(ctx, "unset 1=1"); err == nil {
605		t.Fatalf("Expected unset error for bad syntax but got: %v", buffer.String())
606	}
607
608	if err := repl.OneShot(ctx, `unset "p"`); err == nil {
609		t.Fatalf("Expected unset error for bad syntax but got: %v", buffer.String())
610	}
611
612	buffer.Reset()
613	repl.OneShot(ctx, "p(x) = y { y = x }")
614	repl.OneShot(ctx, "unset p")
615
616	err = repl.OneShot(ctx, "data.repl.p(1, 2)")
617	if err == nil || err.Error() != `1 error occurred: 1:1: rego_type_error: undefined function data.repl.p` {
618		t.Fatalf("Expected eval error (undefined built-in) but got err: '%v'", err)
619	}
620
621	buffer.Reset()
622	repl.OneShot(ctx, "p(1, x) = y { y = x }")
623	repl.OneShot(ctx, "p(2, x) = y { y = x+1 }")
624	repl.OneShot(ctx, "unset p")
625
626	err = repl.OneShot(ctx, "data.repl.p(1, 2, 3)")
627	if err == nil || err.Error() != `1 error occurred: 1:1: rego_type_error: undefined function data.repl.p` {
628		t.Fatalf("Expected eval error (undefined built-in) but got err: '%v'", err)
629	}
630
631	buffer.Reset()
632	repl.OneShot(ctx, `unset q`)
633	if buffer.String() != "warning: no matching rules in current module\n" {
634		t.Fatalf("Expected unset error for missing rule but got: %v", buffer.String())
635	}
636
637	buffer.Reset()
638	repl.OneShot(ctx, `unset q`)
639	if buffer.String() != "warning: no matching rules in current module\n" {
640		t.Fatalf("Expected unset error for missing function but got: %v", buffer.String())
641	}
642
643	buffer.Reset()
644	repl.OneShot(ctx, `magic`)
645	if buffer.String() != "23\n" {
646		t.Fatalf("Expected magic to be defined but got: %v", buffer.String())
647	}
648
649	buffer.Reset()
650	repl.OneShot(ctx, `package data.other`)
651	err = repl.OneShot(ctx, `unset magic`)
652	if buffer.String() != "warning: no matching rules in current module\n" {
653		t.Fatalf("Expected unset error for bad syntax but got: %v", buffer.String())
654	}
655
656	repl.OneShot(ctx, `input = {}`)
657
658	if err := repl.OneShot(ctx, `unset input`); err != nil {
659		t.Fatalf("Expected unset to succeed for input: %v", err)
660	}
661
662	buffer.Reset()
663	repl.OneShot(ctx, `not input`)
664
665	if buffer.String() != "true\n" {
666		t.Fatalf("Expected unset input to remove input document: %v", buffer.String())
667	}
668
669}
670
671func TestOneShotEmptyBufferOneExpr(t *testing.T) {
672	ctx := context.Background()
673	store := newTestStore()
674	var buffer bytes.Buffer
675	repl := newRepl(store, &buffer)
676	repl.OneShot(ctx, "data.a[i].b.c[j] = 2")
677	expectOutput(t, buffer.String(), "+---+---+\n| i | j |\n+---+---+\n| 0 | 1 |\n+---+---+\n")
678	buffer.Reset()
679	repl.OneShot(ctx, "data.a[i].b.c[j] = \"deadbeef\"")
680	expectOutput(t, buffer.String(), "undefined\n")
681}
682
683func TestOneShotEmptyBufferOneRule(t *testing.T) {
684	ctx := context.Background()
685	store := newTestStore()
686	var buffer bytes.Buffer
687	repl := newRepl(store, &buffer)
688	repl.OneShot(ctx, `p[x] { data.a[i] = x }`)
689	expectOutput(t, buffer.String(), "Rule 'p' defined in package repl. Type 'show' to see rules.\n")
690}
691
692func TestOneShotBufferedExpr(t *testing.T) {
693	ctx := context.Background()
694	store := newTestStore()
695	var buffer bytes.Buffer
696	repl := newRepl(store, &buffer)
697	repl.OneShot(ctx, "data.a[i].b.c[j] = ")
698	expectOutput(t, buffer.String(), "")
699	repl.OneShot(ctx, "2")
700	expectOutput(t, buffer.String(), "")
701	repl.OneShot(ctx, "")
702	expectOutput(t, buffer.String(), "+---+---+\n| i | j |\n+---+---+\n| 0 | 1 |\n+---+---+\n")
703}
704
705func TestOneShotBufferedRule(t *testing.T) {
706	ctx := context.Background()
707	store := newTestStore()
708	var buffer bytes.Buffer
709	repl := newRepl(store, &buffer)
710	repl.OneShot(ctx, "p[x] { ")
711	expectOutput(t, buffer.String(), "")
712	repl.OneShot(ctx, "data.a[i].b.c[1]")
713	expectOutput(t, buffer.String(), "")
714	repl.OneShot(ctx, " = ")
715	expectOutput(t, buffer.String(), "")
716	repl.OneShot(ctx, "x")
717	expectOutput(t, buffer.String(), "")
718	repl.OneShot(ctx, "}")
719	expectOutput(t, buffer.String(), "")
720	repl.OneShot(ctx, "")
721	expectOutput(t, buffer.String(), "Rule 'p' defined in package repl. Type 'show' to see rules.\n")
722	buffer.Reset()
723	repl.OneShot(ctx, "p[2]")
724	expectOutput(t, buffer.String(), "2\n")
725}
726
727func TestOneShotJSON(t *testing.T) {
728	ctx := context.Background()
729	store := newTestStore()
730	var buffer bytes.Buffer
731	repl := newRepl(store, &buffer)
732	repl.outputFormat = "json"
733	repl.OneShot(ctx, "data.a[i] = x")
734	var expected interface{}
735	if err := util.UnmarshalJSON([]byte(`{
736		"result": [
737		  {
738			"expressions": [
739			  {
740				"value": true,
741				"text": "data.a[i] = x",
742				"location": {
743				  "row": 1,
744				  "col": 1
745				}
746			  }
747			],
748			"bindings": {
749			  "i": 0,
750			  "x": {
751				"b": {
752				  "c": [
753					true,
754					2,
755					false
756				  ]
757				}
758			  }
759			}
760		  },
761		  {
762			"expressions": [
763			  {
764				"value": true,
765				"text": "data.a[i] = x",
766				"location": {
767				  "row": 1,
768				  "col": 1
769				}
770			  }
771			],
772			"bindings": {
773			  "i": 1,
774			  "x": {
775				"b": {
776				  "c": [
777					false,
778					true,
779					1
780				  ]
781				}
782			  }
783			}
784		  }
785		]
786	  }`), &expected); err != nil {
787		panic(err)
788	}
789
790	var result interface{}
791
792	if err := util.UnmarshalJSON(buffer.Bytes(), &result); err != nil {
793		t.Errorf("Unexpected output format: %v", err)
794		return
795	}
796
797	if !reflect.DeepEqual(expected, result) {
798		t.Errorf("Expected %v but got: %v", expected, buffer.String())
799	}
800}
801
802func TestEvalData(t *testing.T) {
803	ctx := context.Background()
804	store := newTestStore()
805	var buffer bytes.Buffer
806	repl := newRepl(store, &buffer)
807	testMod := []byte(`package ex
808
809p = [1, 2, 3] { true }`)
810
811	txn := storage.NewTransactionOrDie(ctx, store, storage.WriteParams)
812
813	if err := store.UpsertPolicy(ctx, txn, "test", testMod); err != nil {
814		panic(err)
815	}
816
817	if err := store.Commit(ctx, txn); err != nil {
818		panic(err)
819	}
820
821	repl.OneShot(ctx, "data")
822
823	expected := parseJSON(`
824	{
825		"a": [
826			{
827			"b": {
828				"c": [
829				true,
830				2,
831				false
832				]
833			}
834			},
835			{
836			"b": {
837				"c": [
838				false,
839				true,
840				1
841				]
842			}
843			}
844		],
845		"ex": {
846			"p": [
847			1,
848			2,
849			3
850			]
851		}
852	}`)
853	result := parseJSON(buffer.String())
854
855	// Strip REPL documents out as these change depending on build settings.
856	data := result.(map[string]interface{})
857	delete(data, "repl")
858
859	if !reflect.DeepEqual(result, expected) {
860		t.Fatalf("Expected:\n%v\n\nGot:\n%v", expected, result)
861	}
862}
863
864func TestEvalFalse(t *testing.T) {
865	ctx := context.Background()
866	store := newTestStore()
867	var buffer bytes.Buffer
868	repl := newRepl(store, &buffer)
869	repl.OneShot(ctx, "false")
870	result := buffer.String()
871	if result != "false\n" {
872		t.Errorf("Expected result to be false but got: %v", result)
873	}
874}
875
876func TestEvalConstantRule(t *testing.T) {
877	ctx := context.Background()
878	store := newTestStore()
879	var buffer bytes.Buffer
880	repl := newRepl(store, &buffer)
881	repl.OneShot(ctx, "pi = 3.14")
882	result := buffer.String()
883	if result != "Rule 'pi' defined in package repl. Type 'show' to see rules.\n" {
884		t.Errorf("Expected rule to be defined but got: %v", result)
885		return
886	}
887	buffer.Reset()
888	repl.OneShot(ctx, "pi")
889	result = buffer.String()
890	expected := "3.14\n"
891	if result != expected {
892		t.Errorf("Expected pi to evaluate to 3.14 but got: %v", result)
893		return
894	}
895	buffer.Reset()
896	err := repl.OneShot(ctx, "pi.deadbeef")
897	result = buffer.String()
898	if result != "" || !strings.Contains(err.Error(), "undefined ref: data.repl.pi.deadbeef") {
899		t.Fatalf("Expected pi.deadbeef to fail/error but got:\nresult: %q\nerr: %v", result, err)
900	}
901	buffer.Reset()
902	repl.OneShot(ctx, "pi > 3")
903	result = buffer.String()
904	if result != "true\n" {
905		t.Errorf("Expected pi > 3 to be true but got: %v", result)
906		return
907	}
908}
909
910func TestEvalConstantRuleDefaultRootDoc(t *testing.T) {
911	ctx := context.Background()
912	store := newTestStore()
913	var buffer bytes.Buffer
914	repl := newRepl(store, &buffer)
915	repl.OneShot(ctx, "input = 1")
916	buffer.Reset()
917	repl.OneShot(ctx, "input = 2")
918	assertREPLText(t, buffer, "undefined\n")
919	buffer.Reset()
920	repl.OneShot(ctx, "input = 1")
921	assertREPLText(t, buffer, "true\n")
922}
923
924func TestEvalConstantRuleAssignment(t *testing.T) {
925	ctx := context.Background()
926	store := newTestStore()
927	var buffer bytes.Buffer
928
929	defined := "Rule 'x' defined in package repl. Type 'show' to see rules.\n"
930	redefined := "Rule 'x' re-defined in package repl. Type 'show' to see rules.\n"
931	definedInput := "Rule 'input' defined in package repl. Type 'show' to see rules.\n"
932	redefinedInput := "Rule 'input' re-defined in package repl. Type 'show' to see rules.\n"
933
934	repl := newRepl(store, &buffer)
935	repl.OneShot(ctx, "x = 1")
936	assertREPLText(t, buffer, defined)
937	buffer.Reset()
938	repl.OneShot(ctx, "x := 2")
939	assertREPLText(t, buffer, redefined)
940	buffer.Reset()
941
942	repl.OneShot(ctx, "show")
943	assertREPLText(t, buffer, `package repl
944
945x := 2
946`)
947	buffer.Reset()
948
949	repl.OneShot(ctx, "x := 3")
950	assertREPLText(t, buffer, redefined)
951	buffer.Reset()
952	repl.OneShot(ctx, "x")
953	result := buffer.String()
954	if result != "3\n" {
955		t.Fatalf("Expected 3 but got: %v", result)
956	}
957
958	buffer.Reset()
959	repl.OneShot(ctx, "x = 3")
960	result = buffer.String()
961	if result != "true\n" {
962		t.Fatalf("Expected true but got: %v", result)
963	}
964
965	buffer.Reset()
966	repl.OneShot(ctx, "input = 0")
967	assertREPLText(t, buffer, definedInput)
968	buffer.Reset()
969	repl.OneShot(ctx, "input := 1")
970	assertREPLText(t, buffer, redefinedInput)
971	buffer.Reset()
972	repl.OneShot(ctx, "input")
973	result = buffer.String()
974	if result != "1\n" {
975		t.Fatalf("Expected 1 but got: %v", result)
976	}
977
978	buffer.Reset()
979	err := repl.OneShot(ctx, "assign()")
980	if err == nil || !strings.Contains(err.Error(), "too few arguments") {
981		t.Fatal("Expected type check error but got:", err)
982	}
983}
984
985func TestEvalSingleTermMultiValue(t *testing.T) {
986	ctx := context.Background()
987	store := newTestStore()
988	var buffer bytes.Buffer
989	repl := newRepl(store, &buffer)
990	repl.outputFormat = "json"
991
992	input := `{
993		"result": [
994		  {
995			"expressions": [
996			  {
997				"value": true,
998				"text": "data.a[i].b.c[_]",
999				"location": {
1000				  "row": 1,
1001				  "col": 1
1002				}
1003			  }
1004			],
1005			"bindings": {
1006			  "i": 0
1007			}
1008		  },
1009		  {
1010			"expressions": [
1011			  {
1012				"value": 2,
1013				"text": "data.a[i].b.c[_]",
1014				"location": {
1015				  "row": 1,
1016				  "col": 1
1017				}
1018			  }
1019			],
1020			"bindings": {
1021			  "i": 0
1022			}
1023		  },
1024		  {
1025			"expressions": [
1026			  {
1027				"value": true,
1028				"text": "data.a[i].b.c[_]",
1029				"location": {
1030				  "row": 1,
1031				  "col": 1
1032				}
1033			  }
1034			],
1035			"bindings": {
1036			  "i": 1
1037			}
1038		  },
1039		  {
1040			"expressions": [
1041			  {
1042				"value": 1,
1043				"text": "data.a[i].b.c[_]",
1044				"location": {
1045				  "row": 1,
1046				  "col": 1
1047				}
1048			  }
1049			],
1050			"bindings": {
1051			  "i": 1
1052			}
1053		  }
1054		]
1055	  }`
1056
1057	var expected interface{}
1058	if err := util.UnmarshalJSON([]byte(input), &expected); err != nil {
1059		panic(err)
1060	}
1061
1062	repl.OneShot(ctx, "data.a[i].b.c[_]")
1063	var result interface{}
1064	if err := util.UnmarshalJSON(buffer.Bytes(), &result); err != nil {
1065		t.Errorf("Expected valid JSON document: %v: %v", err, buffer.String())
1066		return
1067	}
1068
1069	if !reflect.DeepEqual(expected, result) {
1070		t.Errorf("Expected %v but got: %v", expected, buffer.String())
1071		return
1072	}
1073
1074	buffer.Reset()
1075
1076	repl.OneShot(ctx, "data.deadbeef[x]")
1077	s := buffer.String()
1078	if s != "{}\n" {
1079		t.Errorf("Expected undefined from reference but got: %v", s)
1080		return
1081	}
1082
1083	buffer.Reset()
1084
1085	repl.OneShot(ctx, `p[x] { a = [1, 2, 3, 4]; a[_] = x }`)
1086	buffer.Reset()
1087	repl.OneShot(ctx, "p[x]")
1088
1089	input = `
1090	{
1091		"result": [
1092		  {
1093			"expressions": [
1094			  {
1095				"value": 1,
1096				"text": "p[x]",
1097				"location": {
1098				  "row": 1,
1099				  "col": 1
1100				}
1101			  }
1102			],
1103			"bindings": {
1104			  "x": 1
1105			}
1106		  },
1107		  {
1108			"expressions": [
1109			  {
1110				"value": 2,
1111				"text": "p[x]",
1112				"location": {
1113				  "row": 1,
1114				  "col": 1
1115				}
1116			  }
1117			],
1118			"bindings": {
1119			  "x": 2
1120			}
1121		  },
1122		  {
1123			"expressions": [
1124			  {
1125				"value": 3,
1126				"text": "p[x]",
1127				"location": {
1128				  "row": 1,
1129				  "col": 1
1130				}
1131			  }
1132			],
1133			"bindings": {
1134			  "x": 3
1135			}
1136		  },
1137		  {
1138			"expressions": [
1139			  {
1140				"value": 4,
1141				"text": "p[x]",
1142				"location": {
1143				  "row": 1,
1144				  "col": 1
1145				}
1146			  }
1147			],
1148			"bindings": {
1149			  "x": 4
1150			}
1151		  }
1152		]
1153	}
1154	`
1155
1156	if err := util.UnmarshalJSON([]byte(input), &expected); err != nil {
1157		panic(err)
1158	}
1159
1160	if err := util.UnmarshalJSON(buffer.Bytes(), &result); err != nil {
1161		t.Errorf("Expected valid JSON document: %v: %v", err, buffer.String())
1162		return
1163	}
1164
1165	if !reflect.DeepEqual(expected, result) {
1166		t.Errorf("Exepcted %v but got: %v", expected, buffer.String())
1167	}
1168}
1169
1170func TestEvalSingleTermMultiValueSetRef(t *testing.T) {
1171	ctx := context.Background()
1172	store := newTestStore()
1173	var buffer bytes.Buffer
1174	repl := newRepl(store, &buffer)
1175	repl.outputFormat = "json"
1176	repl.OneShot(ctx, `p[1] { true }`)
1177	repl.OneShot(ctx, `p[2] { true }`)
1178	repl.OneShot(ctx, `q = {3, 4} { true }`)
1179	repl.OneShot(ctx, `r = [x, y] { x = {5, 6}; y = [7, 8] }`)
1180
1181	repl.OneShot(ctx, "p[x]")
1182	expected := parseJSON(`{
1183		"result": [
1184		  {
1185			"expressions": [
1186			  {
1187				"value": 1,
1188				"text": "p[x]",
1189				"location": {
1190				  "row": 1,
1191				  "col": 1
1192				}
1193			  }
1194			],
1195			"bindings": {
1196			  "x": 1
1197			}
1198		  },
1199		  {
1200			"expressions": [
1201			  {
1202				"value": 2,
1203				"text": "p[x]",
1204				"location": {
1205				  "row": 1,
1206				  "col": 1
1207				}
1208			  }
1209			],
1210			"bindings": {
1211			  "x": 2
1212			}
1213		  }
1214		]
1215	  }`)
1216	result := parseJSON(buffer.String())
1217	if !reflect.DeepEqual(result, expected) {
1218		t.Fatalf("Expected %v but got: %v", expected, buffer.String())
1219	}
1220
1221	buffer.Reset()
1222	repl.OneShot(ctx, "q[x]")
1223	expected = parseJSON(`{
1224		"result": [
1225		  {
1226			"expressions": [
1227			  {
1228				"value": 3,
1229				"text": "q[x]",
1230				"location": {
1231				  "row": 1,
1232				  "col": 1
1233				}
1234			  }
1235			],
1236			"bindings": {
1237			  "x": 3
1238			}
1239		  },
1240		  {
1241			"expressions": [
1242			  {
1243				"value": 4,
1244				"text": "q[x]",
1245				"location": {
1246				  "row": 1,
1247				  "col": 1
1248				}
1249			  }
1250			],
1251			"bindings": {
1252			  "x": 4
1253			}
1254		  }
1255		]
1256	  }`)
1257	result = parseJSON(buffer.String())
1258	if !reflect.DeepEqual(result, expected) {
1259		t.Fatalf("Expected %v but got: %v", expected, buffer.String())
1260	}
1261
1262	// Example below shows behavior for ref that iterates an embedded set. The
1263	// tricky part here is that r[_] may refer to multiple collection types. If
1264	// we eventually have a way of distinguishing between the bindings added for
1265	// refs to sets, then those bindings could be filtered out. For now this is
1266	// acceptable, as it should be an edge case.
1267	buffer.Reset()
1268	repl.OneShot(ctx, "r[_][x]")
1269	expected = parseJSON(`{
1270		"result": [
1271		  {
1272			"expressions": [
1273			  {
1274				"value": 5,
1275				"text": "r[_][x]",
1276				"location": {
1277				  "row": 1,
1278				  "col": 1
1279				}
1280			  }
1281			],
1282			"bindings": {
1283			  "x": 5
1284			}
1285		  },
1286		  {
1287			"expressions": [
1288			  {
1289				"value": 6,
1290				"text": "r[_][x]",
1291				"location": {
1292				  "row": 1,
1293				  "col": 1
1294				}
1295			  }
1296			],
1297			"bindings": {
1298			  "x": 6
1299			}
1300		  },
1301		  {
1302			"expressions": [
1303			  {
1304				"value": 7,
1305				"text": "r[_][x]",
1306				"location": {
1307				  "row": 1,
1308				  "col": 1
1309				}
1310			  }
1311			],
1312			"bindings": {
1313			  "x": 0
1314			}
1315		  },
1316		  {
1317			"expressions": [
1318			  {
1319				"value": 8,
1320				"text": "r[_][x]",
1321				"location": {
1322				  "row": 1,
1323				  "col": 1
1324				}
1325			  }
1326			],
1327			"bindings": {
1328			  "x": 1
1329			}
1330		  }
1331		]
1332	  }`)
1333	result = parseJSON(buffer.String())
1334	if !reflect.DeepEqual(result, expected) {
1335		t.Fatalf("Expected %v but got: %v", expected, buffer.String())
1336	}
1337}
1338
1339func TestEvalRuleCompileError(t *testing.T) {
1340	ctx := context.Background()
1341	store := newTestStore()
1342	var buffer bytes.Buffer
1343	repl := newRepl(store, &buffer)
1344	err := repl.OneShot(ctx, `p[x] { true }`)
1345	expected := "x is unsafe"
1346	if !strings.Contains(err.Error(), expected) {
1347		t.Errorf("Expected error to contain %v but got: %v (err: %v)", expected, buffer.String(), err)
1348		return
1349	}
1350	buffer.Reset()
1351	err = repl.OneShot(ctx, `p = true { true }`)
1352	result := buffer.String()
1353	if err != nil || result != "Rule 'p' defined in package repl. Type 'show' to see rules.\n" {
1354		t.Errorf("Expected valid rule to compile (because state should be unaffected) but got: %v (err: %v)", result, err)
1355	}
1356}
1357
1358func TestEvalBodyCompileError(t *testing.T) {
1359	ctx := context.Background()
1360	store := newTestStore()
1361	var buffer bytes.Buffer
1362	repl := newRepl(store, &buffer)
1363	repl.outputFormat = "json"
1364	err := repl.OneShot(ctx, `x = 1; y > x`)
1365	if _, ok := err.(ast.Errors); !ok {
1366		t.Fatalf("Expected error message in output but got`: %v", buffer.String())
1367	}
1368	buffer.Reset()
1369	repl.OneShot(ctx, `x = 1; y = 2; y > x`)
1370	result := util.MustUnmarshalJSON(buffer.Bytes())
1371	exp := util.MustUnmarshalJSON([]byte(`{
1372		"result": [
1373		  {
1374			"expressions": [
1375			  {
1376				"value": true,
1377				"text": "x = 1",
1378				"location": {
1379				  "row": 1,
1380				  "col": 1
1381				}
1382			  },
1383			  {
1384				"value": true,
1385				"text": "y = 2",
1386				"location": {
1387				  "row": 1,
1388				  "col": 8
1389				}
1390			  },
1391			  {
1392				"value": true,
1393				"text": "y \u003e x",
1394				"location": {
1395				  "row": 1,
1396				  "col": 15
1397				}
1398			  }
1399			],
1400			"bindings": {
1401			  "x": 1,
1402			  "y": 2
1403			}
1404		  }
1405		]
1406	  }`))
1407	if !reflect.DeepEqual(exp, result) {
1408		t.Errorf(`Expected %v but got: %v"`, exp, buffer.String())
1409		return
1410	}
1411}
1412
1413func TestEvalBodyContainingWildCards(t *testing.T) {
1414	ctx := context.Background()
1415	store := newTestStore()
1416	var buffer bytes.Buffer
1417	repl := newRepl(store, &buffer)
1418	repl.OneShot(ctx, "data.a[_].b.c[_] = x")
1419	expected := strings.TrimSpace(`
1420+-------+
1421|   x   |
1422+-------+
1423| true  |
1424| 2     |
1425| false |
1426| false |
1427| true  |
1428| 1     |
1429+-------+`)
1430	result := strings.TrimSpace(buffer.String())
1431	if result != expected {
1432		t.Errorf("Expected only a single column of output but got:\n%v", result)
1433	}
1434
1435}
1436
1437func TestEvalBodyInput(t *testing.T) {
1438	ctx := context.Background()
1439	store := newTestStore()
1440	var buffer bytes.Buffer
1441	repl := newRepl(store, &buffer)
1442
1443	repl.OneShot(ctx, `package repl`)
1444	repl.OneShot(ctx, `input["foo.bar"] = "hello" { true }`)
1445	repl.OneShot(ctx, `input["baz"] = data.a[0].b.c[2] { true }`)
1446	repl.OneShot(ctx, `package test`)
1447	repl.OneShot(ctx, "import input.baz")
1448	repl.OneShot(ctx, `p = true { input["foo.bar"] = "hello"; baz = false }`)
1449	buffer.Reset()
1450	repl.OneShot(ctx, "p")
1451
1452	result := buffer.String()
1453	if result != "true\n" {
1454		t.Fatalf("expected true but got: %v", result)
1455	}
1456}
1457
1458func TestEvalBodyInputComplete(t *testing.T) {
1459	ctx := context.Background()
1460	store := newTestStore()
1461	var buffer bytes.Buffer
1462	repl := newRepl(store, &buffer)
1463
1464	// Test that input can be defined completely:
1465	// https://github.com/open-policy-agent/opa/issues/231
1466	repl.OneShot(ctx, `package repl`)
1467	repl.OneShot(ctx, `input = 1`)
1468	buffer.Reset()
1469	repl.OneShot(ctx, `input`)
1470
1471	result := buffer.String()
1472	if result != "1\n" {
1473		t.Fatalf("Expected 1 but got: %v", result)
1474	}
1475
1476	buffer.Reset()
1477
1478	// Test that input is as expected
1479	repl.OneShot(ctx, `package ex1`)
1480	repl.OneShot(ctx, `x = input`)
1481	buffer.Reset()
1482	repl.OneShot(ctx, `x`)
1483
1484	result = buffer.String()
1485	if result != "1\n" {
1486		t.Fatalf("Expected 1 but got: %v", result)
1487	}
1488
1489	// Test that local input replaces other inputs
1490	repl.OneShot(ctx, `package ex2`)
1491	repl.OneShot(ctx, `input = 2`)
1492	buffer.Reset()
1493	repl.OneShot(ctx, `input`)
1494
1495	result = buffer.String()
1496
1497	if result != "2\n" {
1498		t.Fatalf("Expected 2 but got: %v", result)
1499	}
1500
1501	buffer.Reset()
1502
1503	// Test that original input is intact
1504	repl.OneShot(ctx, `package ex3`)
1505	repl.OneShot(ctx, `input`)
1506
1507	result = buffer.String()
1508
1509	if result != "1\n" {
1510		t.Fatalf("Expected 1 but got: %v", result)
1511	}
1512
1513	// Test that deferencing undefined input results in undefined
1514	buffer.Reset()
1515
1516	repl = newRepl(store, &buffer)
1517	repl.OneShot(ctx, `input.p`)
1518	result = buffer.String()
1519	if result != "undefined\n" {
1520		t.Fatalf("Expected undefined but got: %v", result)
1521	}
1522
1523	buffer.Reset()
1524	repl.OneShot(ctx, `input.p = false`)
1525	result = buffer.String()
1526	if result != "undefined\n" {
1527		t.Fatalf("Expected undefined but got: %v", result)
1528	}
1529
1530}
1531
1532func TestEvalBodyWith(t *testing.T) {
1533	ctx := context.Background()
1534	store := newTestStore()
1535	var buffer bytes.Buffer
1536	repl := newRepl(store, &buffer)
1537
1538	repl.OneShot(ctx, `p = true { input.foo = "bar" }`)
1539	buffer.Reset()
1540	repl.OneShot(ctx, "p")
1541
1542	if buffer.String() != "undefined\n" {
1543		t.Fatalf("Expected undefined but got: %v", buffer.String())
1544	}
1545
1546	buffer.Reset()
1547
1548	repl.OneShot(ctx, `p with input.foo as "bar"`)
1549
1550	result := buffer.String()
1551	expected := "true\n"
1552
1553	if result != expected {
1554		t.Fatalf("Expected true but got: %v", result)
1555	}
1556}
1557
1558func TestEvalBodyRewrittenBuiltin(t *testing.T) {
1559	ctx := context.Background()
1560	store := newTestStore()
1561	var buffer bytes.Buffer
1562	repl := newRepl(store, &buffer)
1563	repl.OneShot(ctx, "json")
1564	repl.OneShot(ctx, `p[x] { a[x]; a = [1,2,3,4] }`)
1565	repl.OneShot(ctx, "p[x] > 1")
1566	result := util.MustUnmarshalJSON(buffer.Bytes())
1567	expected := util.MustUnmarshalJSON([]byte(`{
1568		"result": [
1569		  {
1570			"expressions": [
1571			  {
1572				"value": true,
1573				"text": "p[x] \u003e 1",
1574				"location": {
1575				  "row": 1,
1576				  "col": 1
1577				}
1578			  }
1579			],
1580			"bindings": {
1581			  "x": 2
1582			}
1583		  },
1584		  {
1585			"expressions": [
1586			  {
1587				"value": true,
1588				"text": "p[x] \u003e 1",
1589				"location": {
1590				  "row": 1,
1591				  "col": 1
1592				}
1593			  }
1594			],
1595			"bindings": {
1596			  "x": 3
1597			}
1598		  }
1599		]
1600	  }`))
1601	if util.Compare(result, expected) != 0 {
1602		t.Fatalf("Expected %v but got: %v", expected, buffer.String())
1603	}
1604}
1605
1606func TestEvalBodyRewrittenRef(t *testing.T) {
1607	ctx := context.Background()
1608	store := newTestStore()
1609	var buffer bytes.Buffer
1610	repl := newRepl(store, &buffer)
1611	repl.OneShot(ctx, "json")
1612	repl.OneShot(ctx, `i = 1`)
1613	repl.OneShot(ctx, `data.a[0].b.c[i]`)
1614	result := util.MustUnmarshalJSON(buffer.Bytes())
1615	expected := util.MustUnmarshalJSON([]byte(`{
1616		"result": [
1617		  {
1618			"expressions": [
1619			  {
1620				"value": 2,
1621				"text": "data.a[0].b.c[i]",
1622				"location": {
1623				  "row": 1,
1624				  "col": 1
1625				}
1626			  }
1627			]
1628		  }
1629		]
1630	  }`))
1631	if util.Compare(result, expected) != 0 {
1632		t.Fatalf("Expected %v but got: %v", expected, buffer.String())
1633	}
1634	buffer.Reset()
1635	repl.OneShot(ctx, "p = {1,2,3}")
1636	repl.OneShot(ctx, "p")
1637	result = util.MustUnmarshalJSON(buffer.Bytes())
1638	expected = util.MustUnmarshalJSON([]byte(`{
1639		"result": [
1640		  {
1641			"expressions": [
1642			  {
1643				"value": [
1644				  1,
1645				  2,
1646				  3
1647				],
1648				"text": "p",
1649				"location": {
1650				  "row": 1,
1651				  "col": 1
1652				}
1653			  }
1654			]
1655		  }
1656		]
1657	  }`))
1658	if util.Compare(result, expected) != 0 {
1659		t.Fatalf("Expected %v but got: %v", expected, buffer.String())
1660	}
1661	buffer.Reset()
1662	repl.OneShot(ctx, "p[x]")
1663	result = util.MustUnmarshalJSON(buffer.Bytes())
1664	expected = util.MustUnmarshalJSON([]byte(`{
1665		"result": [
1666		  {
1667			"expressions": [
1668			  {
1669				"value": 1,
1670				"text": "p[x]",
1671				"location": {
1672				  "row": 1,
1673				  "col": 1
1674				}
1675			  }
1676			],
1677			"bindings": {
1678			  "x": 1
1679			}
1680		  },
1681		  {
1682			"expressions": [
1683			  {
1684				"value": 2,
1685				"text": "p[x]",
1686				"location": {
1687				  "row": 1,
1688				  "col": 1
1689				}
1690			  }
1691			],
1692			"bindings": {
1693			  "x": 2
1694			}
1695		  },
1696		  {
1697			"expressions": [
1698			  {
1699				"value": 3,
1700				"text": "p[x]",
1701				"location": {
1702				  "row": 1,
1703				  "col": 1
1704				}
1705			  }
1706			],
1707			"bindings": {
1708			  "x": 3
1709			}
1710		  }
1711		]
1712	  }`))
1713	if util.Compare(result, expected) != 0 {
1714		t.Fatalf("Expected %v but got: %v", expected, buffer.String())
1715	}
1716}
1717
1718func TestEvalBodySomeDecl(t *testing.T) {
1719	ctx := context.Background()
1720	store := newTestStore()
1721	var buffer bytes.Buffer
1722	repl := newRepl(store, &buffer)
1723	repl.OneShot(ctx, "json")
1724	repl.OneShot(ctx, "some x; x = 1")
1725	exp := util.MustUnmarshalJSON([]byte(`{
1726		"result": [
1727			{
1728				"expressions": [
1729					{
1730						"value": true,
1731						"text": "x = 1",
1732						"location": {
1733							"row": 1,
1734							"col": 9
1735						}
1736					}
1737				],
1738				"bindings": {
1739					"x": 1
1740				}
1741			}
1742		]
1743	}`))
1744	result := util.MustUnmarshalJSON(buffer.Bytes())
1745	if util.Compare(result, exp) != 0 {
1746		t.Fatalf("Expected %v but got: %v", exp, result)
1747	}
1748}
1749
1750func TestEvalImport(t *testing.T) {
1751	ctx := context.Background()
1752	store := newTestStore()
1753	var buffer bytes.Buffer
1754	repl := newRepl(store, &buffer)
1755	repl.OneShot(ctx, "import data.a")
1756	if len(buffer.Bytes()) != 0 {
1757		t.Errorf("Expected no output but got: %v", buffer.String())
1758		return
1759	}
1760	buffer.Reset()
1761	repl.OneShot(ctx, "a[0].b.c[0] = true")
1762	result := buffer.String()
1763	expected := "true\n"
1764	if result != expected {
1765		t.Errorf("Expected expression to evaluate successfully but got: %v", result)
1766		return
1767	}
1768
1769	// https://github.com/open-policy-agent/opa/issues/158 - re-run query to
1770	// make sure import is not lost
1771	buffer.Reset()
1772	repl.OneShot(ctx, "a[0].b.c[0] = true")
1773	result = buffer.String()
1774	expected = "true\n"
1775	if result != expected {
1776		t.Fatalf("Expected expression to evaluate successfully but got: %v", result)
1777	}
1778}
1779
1780func TestEvalPackage(t *testing.T) {
1781	ctx := context.Background()
1782	store := newTestStore()
1783	var buffer bytes.Buffer
1784	repl := newRepl(store, &buffer)
1785	repl.OneShot(ctx, `package foo.bar`)
1786	repl.OneShot(ctx, `p = true { true }`)
1787	repl.OneShot(ctx, `package baz.qux`)
1788	buffer.Reset()
1789	err := repl.OneShot(ctx, "p")
1790	if !strings.Contains(err.Error(), "p is unsafe") {
1791		t.Fatalf("Expected unsafe variable error but got: %v", err)
1792	}
1793	repl.OneShot(ctx, "import data.foo.bar.p")
1794	buffer.Reset()
1795	repl.OneShot(ctx, "p")
1796	if buffer.String() != "true\n" {
1797		t.Errorf("Expected expression to eval successfully but got: %v", buffer.String())
1798		return
1799	}
1800}
1801
1802func TestMetrics(t *testing.T) {
1803	ctx := context.Background()
1804	store := newTestStore()
1805	var buffer bytes.Buffer
1806
1807	repl := newRepl(store, &buffer)
1808	repl.OneShot(ctx, "a = {[1,2], [3,4]}")
1809	repl.OneShot(ctx, "metrics")
1810	repl.OneShot(ctx, `[x | a[x]]`)
1811	if !strings.Contains(buffer.String(), "timer_rego_query_compile_ns") {
1812		t.Fatal("Expected output to contain well known metric key but got:", buffer.String())
1813	}
1814
1815	buffer.Reset()
1816	repl.OneShot(ctx, `[x | a[x]]`)
1817	if !strings.Contains(buffer.String(), "timer_rego_query_compile_ns") {
1818		t.Fatal("Expected output to contain well known metric key but got:", buffer.String())
1819	}
1820
1821	buffer.Reset()
1822	repl.OneShot(ctx, "metrics")
1823	repl.OneShot(ctx, `[x | a[x]]`)
1824
1825	expected := `[
1826  [
1827    1,
1828    2
1829  ],
1830  [
1831    3,
1832    4
1833  ]
1834]
1835`
1836
1837	if expected != buffer.String() {
1838		t.Fatalf("Expected output to be exactly:\n%v\n\nGot:\n\n%v\n", expected, buffer.String())
1839	}
1840}
1841
1842func TestProfile(t *testing.T) {
1843	store := newTestStore()
1844	ctx := context.Background()
1845	txn := storage.NewTransactionOrDie(ctx, store, storage.WriteParams)
1846	const numLines = 21
1847
1848	mod2 := []byte(`package rbac
1849
1850		input = {
1851		"subject": "bob",
1852			"resource": "foo123",
1853			"action": "write",
1854	}
1855		bindings = [
1856	{
1857		"user": "alice",
1858		"roles": ["dev", "test"],
1859	},
1860	{
1861		"user": "bob",
1862		"roles": ["test"],
1863	},
1864]
1865
1866	roles = [
1867	{
1868		"name": "dev",
1869		"permissions": [
1870		{"resource": "foo123", "action": "write"},
1871		{"resource": "foo123", "action": "read"},
1872	],
1873	},
1874	{
1875		"name": "test",
1876		"permissions": [{"resource": "foo123", "action": "read"}],
1877	},
1878]
1879
1880default allow = false
1881
1882	allow {
1883	user_has_role[role_name]
1884	role_has_permission[role_name]
1885	}
1886
1887	user_has_role[role_name] {
1888	binding := bindings[_]
1889	binding.user = input.subject
1890	role_name := binding.roles[_]
1891	}
1892
1893	role_has_permission[role_name] {
1894	role := roles[_]
1895	role_name := role.name
1896	perm := role.permissions[_]
1897	perm.resource = input.resource
1898	perm.action = input.action
1899	}`)
1900
1901	if err := store.UpsertPolicy(ctx, txn, "mod2", mod2); err != nil {
1902		panic(err)
1903	}
1904	if err := store.Commit(ctx, txn); err != nil {
1905		panic(err)
1906	}
1907
1908	var buffer bytes.Buffer
1909	repl := newRepl(store, &buffer)
1910	repl.OneShot(ctx, "profile")
1911	repl.OneShot(ctx, "data.rbac.allow")
1912	result := buffer.String()
1913	lines := strings.Split(result, "\n")
1914	if len(lines) != numLines {
1915		t.Fatal("Expected 21 lines, got :", len(lines))
1916	}
1917	buffer.Reset()
1918}
1919
1920func TestInstrument(t *testing.T) {
1921	ctx := context.Background()
1922	store := newTestStore()
1923	var buffer bytes.Buffer
1924
1925	repl := newRepl(store, &buffer)
1926
1927	// Turn on instrumentation w/o turning on metrics.
1928	repl.OneShot(ctx, "instrument")
1929	repl.OneShot(ctx, "true")
1930
1931	result := buffer.String()
1932
1933	if !strings.Contains(result, "histogram_eval_op_plug") {
1934		t.Fatal("Expected plug histogram in output but got:", result)
1935	}
1936
1937	buffer.Reset()
1938
1939	// Turn off instrumentation.
1940	repl.OneShot(ctx, "instrument")
1941	repl.OneShot(ctx, "true")
1942
1943	result = buffer.String()
1944
1945	if strings.Contains(result, "histogram_eval_op_plug") {
1946		t.Fatal("Expected instrumentation to be turned off but got:", result)
1947	}
1948
1949	buffer.Reset()
1950
1951	// Turn on metrics and then turn on instrumentation.
1952	repl.OneShot(ctx, "metrics")
1953	repl.OneShot(ctx, "true")
1954
1955	result = buffer.String()
1956
1957	if strings.Contains(result, "histogram_eval_op_plug") {
1958		t.Fatal("Expected instrumentation to be turned off but got:", result)
1959	}
1960
1961	if !strings.Contains(result, "timer_rego_query_eval_ns") {
1962		t.Fatal("Expected metrics to be turned on but got:", result)
1963	}
1964
1965	buffer.Reset()
1966
1967	repl.OneShot(ctx, "instrument")
1968	repl.OneShot(ctx, "true")
1969
1970	result = buffer.String()
1971
1972	if !strings.Contains(result, "histogram_eval_op_plug") {
1973		t.Fatal("Expected instrumentation to be turned on but got:", result)
1974	}
1975
1976	if !strings.Contains(result, "timer_rego_query_eval_ns") {
1977		t.Fatal("Expected metrics to be turned on but got:", result)
1978	}
1979
1980}
1981
1982func TestEvalTrace(t *testing.T) {
1983	ctx := context.Background()
1984	store := newTestStore()
1985	var buffer bytes.Buffer
1986	repl := newRepl(store, &buffer)
1987	repl.OneShot(ctx, "trace")
1988	repl.OneShot(ctx, `data.a[i].b.c[j] = x; data.a[k].b.c[x] = 1`)
1989	expected := strings.TrimSpace(`
1990query:1     Enter data.a[i].b.c[j] = x; data.a[k].b.c[x] = 1
1991query:1     | Eval data.a[i].b.c[j] = x
1992query:1     | Eval data.a[k].b.c[x] = 1
1993query:1     | Fail data.a[k].b.c[x] = 1
1994query:1     | Redo data.a[i].b.c[j] = x
1995query:1     | Eval data.a[k].b.c[x] = 1
1996query:1     | Exit data.a[i].b.c[j] = x; data.a[k].b.c[x] = 1
1997query:1     Redo data.a[i].b.c[j] = x; data.a[k].b.c[x] = 1
1998query:1     | Redo data.a[k].b.c[x] = 1
1999query:1     | Redo data.a[i].b.c[j] = x
2000query:1     | Eval data.a[k].b.c[x] = 1
2001query:1     | Fail data.a[k].b.c[x] = 1
2002query:1     | Redo data.a[i].b.c[j] = x
2003query:1     | Eval data.a[k].b.c[x] = 1
2004query:1     | Fail data.a[k].b.c[x] = 1
2005query:1     | Redo data.a[i].b.c[j] = x
2006query:1     | Eval data.a[k].b.c[x] = 1
2007query:1     | Fail data.a[k].b.c[x] = 1
2008query:1     | Redo data.a[i].b.c[j] = x
2009query:1     | Eval data.a[k].b.c[x] = 1
2010query:1     | Fail data.a[k].b.c[x] = 1
2011query:1     | Redo data.a[i].b.c[j] = x
2012+---+---+---+---+
2013| i | j | k | x |
2014+---+---+---+---+
2015| 0 | 1 | 1 | 2 |
2016+---+---+---+---+`)
2017	expected += "\n"
2018
2019	if expected != buffer.String() {
2020		t.Fatalf("Expected output to be exactly:\n%v\n\nGot:\n\n%v\n", expected, buffer.String())
2021	}
2022}
2023
2024func TestEvalNotes(t *testing.T) {
2025	ctx := context.Background()
2026	store := newTestStore()
2027	var buffer bytes.Buffer
2028	repl := newRepl(store, &buffer)
2029	repl.OneShot(ctx, `p { a = [1,2,3]; a[i] = x; x > 1; trace(sprintf("x = %d", [x])) }`)
2030	repl.OneShot(ctx, "notes")
2031	buffer.Reset()
2032	repl.OneShot(ctx, "p")
2033	expected := strings.TrimSpace(`query:1     Enter data.repl.p = _
2034query:1     | Enter data.repl.p
2035note        | | Note "x = 2"
2036query:1     Redo data.repl.p = _
2037query:1     | Redo data.repl.p
2038note        | | Note "x = 3"
2039true`)
2040	expected += "\n"
2041	if expected != buffer.String() {
2042		t.Fatalf("Expected output to be exactly:\n%v\n\nGot:\n\n%v\n", expected, buffer.String())
2043	}
2044}
2045
2046func TestTruncatePrettyOutput(t *testing.T) {
2047	ctx := context.Background()
2048	store := inmem.New()
2049	var buffer bytes.Buffer
2050	repl := newRepl(store, &buffer)
2051	repl.prettyLimit = 1000 // crank up limit to test repl command
2052	repl.OneShot(ctx, "pretty-limit 80")
2053	repl.OneShot(ctx, "data[x]")
2054	for _, line := range strings.Split(buffer.String(), "\n") {
2055		// | "repl" | {"version": <elided>... |
2056		if len(line) > 96 {
2057			t.Fatalf("Expected len(line) to be < 96 but got:\n\n%v", buffer)
2058		}
2059	}
2060	buffer.Reset()
2061	if err := repl.OneShot(ctx, "pretty-limit"); err == nil || !strings.Contains(err.Error(), "usage: pretty-limit <n>") {
2062		t.Fatalf("Expected usage error but got: %v", err)
2063	}
2064}
2065
2066func TestUnsetPackage(t *testing.T) {
2067	ctx := context.Background()
2068	store := inmem.New()
2069	var buffer bytes.Buffer
2070	repl := newRepl(store, &buffer)
2071
2072	repl.OneShot(ctx, "package a")
2073	if err := repl.OneShot(ctx, `unset-package 5`); err == nil {
2074		t.Fatalf("Expected package-unset error for bad package but got: %v", buffer.String())
2075	}
2076
2077	buffer.Reset()
2078
2079	repl.OneShot(ctx, "package a")
2080	repl.OneShot(ctx, "unset-package b")
2081	if buffer.String() != "warning: no matching package\n" {
2082		t.Fatalf("Expected unset-package warning no matching package but got: %v", buffer.String())
2083	}
2084
2085	buffer.Reset()
2086
2087	repl.OneShot(ctx, `package a`)
2088	if err := repl.OneShot(ctx, `unset-package b`); err != nil {
2089		t.Fatalf("Expected unset-package to succeed for input: %v", err)
2090	}
2091
2092	buffer.Reset()
2093
2094	repl.OneShot(ctx, "package a")
2095	repl.OneShot(ctx, "unset-package a")
2096	repl.OneShot(ctx, "show")
2097	if buffer.String() != "no rules defined\n" {
2098		t.Fatalf("Expected unset-package to return to default but got: %v", buffer.String())
2099	}
2100}
2101
2102func assertREPLText(t *testing.T, buf bytes.Buffer, expected string) {
2103	t.Helper()
2104	result := buf.String()
2105	if result != expected {
2106		t.Fatalf("Expected:\n%v\n\nString:\n\n%v\nGot:\n%v\n\nString:\n\n%v", []byte(expected), expected, []byte(result), result)
2107	}
2108}
2109
2110func expectOutput(t *testing.T, output string, expected string) {
2111	t.Helper()
2112	if output != expected {
2113		t.Errorf("Repl output: expected %#v but got %#v", expected, output)
2114	}
2115}
2116
2117func newRepl(store storage.Store, buffer *bytes.Buffer) *REPL {
2118	repl := New(store, "", buffer, "", 0, "")
2119	return repl
2120}
2121
2122func newTestStore() storage.Store {
2123	input := `
2124    {
2125        "a": [
2126            {
2127                "b": {
2128                    "c": [true,2,false]
2129                }
2130            },
2131            {
2132                "b": {
2133                    "c": [false,true,1]
2134                }
2135            }
2136        ]
2137    }
2138    `
2139	var data map[string]interface{}
2140	err := util.UnmarshalJSON([]byte(input), &data)
2141	if err != nil {
2142		panic(err)
2143	}
2144	return inmem.NewFromObject(data)
2145}
2146
2147func parseJSON(s string) interface{} {
2148	var v interface{}
2149	if err := util.UnmarshalJSON([]byte(s), &v); err != nil {
2150		panic(err)
2151	}
2152	return v
2153}
2154