package lighthouse import ( "context" "math" "reflect" "testing" ) // TestChannelIDMatchesPHP pins ChannelID to PHP's (int) cast of the id // segment. The expected values were printed by PHP 8.5.10: // // php -r 'foreach ([...] as $s) var_dump((int)$s);' func TestChannelIDMatchesPHP(t *testing.T) { cases := []struct { segment string want int64 }{ {"5", 5}, {"05", 5}, {" 5", 5}, {"5abc", 5}, {"abc", 0}, {"-3", -3}, {"", 0}, {"1e3", 1000}, {"0x1A", 0}, {"9999999999999999999", math.MaxInt64}, {"\t5", 5}, {"\n5", 5}, {"5 ", 5}, {"+5", 5}, {" -7x", -7}, {"1.9", 1}, {"-0", 0}, {"1e20", math.MaxInt64}, {"0b11", 0}, {"٥", 0}, {" ", 0}, {"-9999999999999999999", math.MinInt64}, {"-1e20", math.MinInt64}, {"1e-3", 0}, {".5", 0}, {"5.", 5}, {"1e", 1}, {"1e+2", 100}, {"\v5", 5}, {"\f5", 5}, {"\r5", 5}, {"NaN", 0}, {"INF", 0}, {"1E3", 1000}, {"9223372036854775807", math.MaxInt64}, {"9223372036854775808", math.MaxInt64}, {"1.5e3", 1500}, {"-.5e1", -5}, {"0005", 5}, {"00", 0}, {"- 5", 0}, {"5e3abc", 5000}, {"12.7e1x", 127}, {"1e400", 0}, } for _, tc := range cases { if got := ChannelID("collection:" + tc.segment); got != tc.want { t.Errorf("ChannelID(collection:%q) = %d, want %d", tc.segment, got, tc.want) } } if got := ChannelID("collection"); got != 0 { t.Errorf("missing segment = %d, want 0", got) } if got := ChannelID("presence:collection:5"); got != 0 { t.Errorf("presence:collection:5 = %d, want 0 (segment 1 is \"collection\")", got) } if got := ChannelID("wishlist:12:extra"); got != 12 { t.Errorf("wishlist:12:extra = %d, want 12", got) } } func TestParseChannel(t *testing.T) { cases := []struct { channel string namespace string presence bool }{ {"collection:5", "collection", false}, {"ns:entity:id", "ns", false}, {"presence:acme:room:1", "acme", true}, {"presence:collection:5", "collection", true}, {"presence:presence:x", "", true}, {"a:b:c:d", "", false}, {"presence:a:b:c:d", "", true}, {"", "", false}, {":5", "", false}, {"Collection:5", "Collection", false}, } for _, tc := range cases { ns, presence := ParseChannel(tc.channel) if ns != tc.namespace || presence != tc.presence { t.Errorf("ParseChannel(%q) = (%q, %t), want (%q, %t)", tc.channel, ns, presence, tc.namespace, tc.presence) } } } func TestFormatChannels(t *testing.T) { got := FormatChannels("Acme", []string{"Collection:5", "acme:user:1", "ACME:x"}) want := []string{"acme:collection:5", "acme:user:1", "acme:x"} if !reflect.DeepEqual(got, want) { t.Fatalf("FormatChannels = %v, want %v", got, want) } if got := FormatChannels("", []string{"Collection:5"}); !reflect.DeepEqual(got, []string{"collection:5"}) { t.Fatalf("no namespace = %v", got) } // PHP treats the namespace "0" as empty; the prefix is applied once. if got := FormatChannels("0", []string{"Room:1"}); !reflect.DeepEqual(got, []string{"room:1"}) { t.Fatalf("namespace 0 = %v", got) } if got := FormatChannels("acme", []string{"ACME:room:1", "acme:acme:x"}); !reflect.DeepEqual(got, []string{"acme:room:1", "acme:acme:x"}) { t.Fatalf("prefix once = %v", got) } if got := FormatChannels("acme", nil); len(got) != 0 { t.Fatalf("nil channels = %v", got) } } func TestClientID(t *testing.T) { if ClientID(nil) != "" || ClientID(WithClientID(nil, "c-0")) != "c-0" { t.Fatal("nil ctx handling") } if ClientID(context.Background()) != "" { t.Fatal("empty ctx has a client id") } if got := ClientID(WithClientID(context.Background(), "c-1")); got != "c-1" { t.Fatalf("ClientID = %q", got) } }