review

review patchsets using your default editor
Log | Files | Refs

provider_test.odin (4425B)


      1 package provider
      2 
      3 import "core:strings"
      4 import "core:testing"
      5 
      6 @(test)
      7 names_carry_the_model :: proc(t: ^testing.T) {
      8 	testing.expect_value(
      9 		t,
     10 		name(Provider{kind = .Claude, model = "sonnet"}, context.temp_allocator),
     11 		"claude/sonnet",
     12 	)
     13 	testing.expect_value(
     14 		t,
     15 		name(Provider{kind = .Pi, model = "glm", upstream = "maple"}, context.temp_allocator),
     16 		"pi/maple/glm",
     17 	)
     18 	testing.expect_value(t, name(Provider{kind = .Pi}, context.temp_allocator), "pi")
     19 	testing.expect_value(
     20 		t,
     21 		name(Provider{kind = .Api, model = "claude-sonnet-5"}, context.temp_allocator),
     22 		"api/claude-sonnet-5",
     23 	)
     24 	testing.expect_value(
     25 		t,
     26 		name(Provider{kind = .Command, argv = {"echo", "x"}}, context.temp_allocator),
     27 		"command: echo x",
     28 	)
     29 	p, ok := build("api", "", context.temp_allocator)
     30 	testing.expect(t, ok)
     31 	testing.expect_value(t, p.model, default_api_model)
     32 	_, ok = build("nothing", "", context.temp_allocator)
     33 	testing.expect(t, !ok)
     34 }
     35 
     36 @(test)
     37 the_chain_tries_the_assistant_between_api_and_gateway :: proc(t: ^testing.T) {
     38 	chain := default_chain(context.temp_allocator)
     39 	testing.expect_value(t, len(chain), 3)
     40 	testing.expect_value(t, chain[0].provider.kind, Kind.Api)
     41 	testing.expect_value(t, chain[1].name, "claude/sonnet")
     42 	testing.expect_value(t, chain[2].provider.kind, Kind.Pi)
     43 }
     44 
     45 @(test)
     46 pi_answers_from_its_stream :: proc(t: ^testing.T) {
     47 	out := `{"type":"message_start"}
     48 {"type":"message_end","message":{"role":"assistant","content":[{"type":"text","text":"{\"findings\":[]}"}],"usage":{"input":10,"output":2,"cacheRead":1,"cost":{"total":0.5}},"stopReason":"stop"}}
     49 `
     50 	answer, err := spoken(out, context.temp_allocator)
     51 	testing.expect_value(t, err, "")
     52 	testing.expect_value(t, answer.text, `{"findings":[]}`)
     53 	testing.expect_value(t, answer.tokens_in, 10)
     54 	testing.expect_value(t, answer.cost, 0.5)
     55 	_, err = spoken("Error: no provider\nmore prose\n", context.temp_allocator)
     56 	testing.expect_value(t, err, "Error: no provider more prose")
     57 	_, err = spoken(
     58 		`{"type":"message_end","message":{"role":"assistant","stopReason":"error","errorMessage":"rate limited"}}`,
     59 		context.temp_allocator,
     60 	)
     61 	testing.expect_value(t, err, "rate limited")
     62 }
     63 
     64 @(test)
     65 command_answers_whole_or_by_field :: proc(t: ^testing.T) {
     66 	p := Provider {
     67 		kind = .Command,
     68 		argv = {"cat"},
     69 	}
     70 	answer, err := ask(p, "system", "user", context.temp_allocator)
     71 	testing.expect_value(t, err, "")
     72 	testing.expect_value(t, answer.text, "system\n\nuser")
     73 	fielded := Provider {
     74 		kind  = .Command,
     75 		argv  = {"echo", `{"answer":"hello","other":1}`},
     76 		field = "answer",
     77 	}
     78 	answer, err = ask(fielded, "s", "u", context.temp_allocator)
     79 	testing.expect_value(t, err, "")
     80 	testing.expect_value(t, answer.text, "hello")
     81 	testing.expect_value(t, field("not json", "answer", context.temp_allocator), "not json")
     82 	_, err = ask(Provider{kind = .Command}, "s", "u", context.temp_allocator)
     83 	testing.expect(t, strings.contains(err, "names no command"))
     84 	_, err = ask(p, "s", "  \n", context.temp_allocator)
     85 	testing.expect_value(t, err, "nothing to ask: the prompt is empty")
     86 	_, err = ask(Provider{kind = .Command, argv = {"false"}}, "s", "u", context.temp_allocator)
     87 	testing.expect(t, strings.contains(err, "exit 1"))
     88 }
     89 
     90 @(test)
     91 api_requests_and_replies_are_shaped :: proc(t: ^testing.T) {
     92 	body := request(
     93 		"claude-sonnet-5",
     94 		"sys \"quoted\"",
     95 		"user\nline",
     96 		findings_tool,
     97 		context.temp_allocator,
     98 	)
     99 	for want in ([]string{`"model":"claude-sonnet-5"`, `"text":"sys \"quoted\""`, `"cache_control":{"type":"ephemeral"}`, `"strict":true`, `"name":"report_findings"`, `"text":"user\nline"`, `"temperature":0`}) {
    100 		testing.expectf(t, strings.contains(body, want), "%s missing from %s", want, body)
    101 	}
    102 	answer, err := reply(
    103 		`{"content":[{"type":"text","text":"hi"},{"type":"tool_use","id":"x","name":"report_findings","input":{"findings":[{"rule":"a","message":"b}"}]}}],"usage":{"input_tokens":5,"output_tokens":3,"cache_read_input_tokens":2}}`,
    104 		context.temp_allocator,
    105 	)
    106 	testing.expect_value(t, err, "")
    107 	testing.expect_value(t, answer.text, `{"findings":[{"rule":"a","message":"b}"}]}`)
    108 	testing.expect_value(t, answer.tokens_in, 5)
    109 	testing.expect_value(t, answer.cached, 2)
    110 	_, err = reply(`{"content":[{"type":"text","text":"hi"}],"usage":{}}`, context.temp_allocator)
    111 	testing.expect_value(t, err, "the model answered without reporting")
    112 	testing.expect_value(t, error_of(`{"error":{"message":"bad key"}}`), "bad key")
    113 }