package byd import ( "encoding/json" "regexp" "strconv" "testing" ) // TestDeviceIsStable is the point of the whole seeded-derivation approach: a // restart must not look like a new phone to BYD. func TestDeviceIsStable(t *testing.T) { a, err := NewDevice("user@example.com") if err != nil { t.Fatal(err) } b, err := NewDevice("user@example.com") if err != nil { t.Fatal(err) } if a != b { t.Errorf("same seed gave different devices:\n%+v\n%+v", a, b) } c, err := NewDevice("other@example.com") if err != nil { t.Fatal(err) } if c.IMEI == a.IMEI { t.Error("different seeds produced the same IMEI") } } func TestDeviceLooksRealistic(t *testing.T) { d, err := NewDevice("user@example.com") if err != nil { t.Fatal(err) } if !regexp.MustCompile(`^\d{15}$`).MatchString(d.IMEI) { t.Errorf("IMEI %q is not 15 digits", d.IMEI) } if got, want := luhn(d.IMEI[:14]), string(d.IMEI[14]); got != want { t.Errorf("IMEI %q fails the Luhn check (want check digit %s)", d.IMEI, got) } if !regexp.MustCompile(`^([0-9a-f]{2}:){5}[0-9a-f]{2}$`).MatchString(d.MAC) { t.Errorf("MAC %q is malformed", d.MAC) } if !regexp.MustCompile(`^[0-9a-f]{32}$`).MatchString(d.IMEIMD5) { t.Errorf("IMEIMD5 %q is not a lowercase MD5", d.IMEIMD5) } for name, v := range map[string]string{ "Model": d.Model, "MobileBrand": d.MobileBrand, "MobileModel": d.MobileModel, "Mod": d.Mod, "SDK": d.SDK, "AndroidVer": d.AndroidVer, } { if v == "" { t.Errorf("%s is empty", name) } } } // TestDeviceMACIsLocallyAdministered keeps the generated address out of the // space of real vendor MACs. func TestDeviceMACIsLocallyAdministered(t *testing.T) { for _, seed := range []string{"a", "b", "c", "d", "e"} { d, err := NewDevice(seed) if err != nil { t.Fatal(err) } first, err := strconv.ParseInt(d.MAC[:2], 16, 16) if err != nil { t.Fatalf("MAC %q: %v", d.MAC, err) } if first&0x02 == 0 { t.Errorf("MAC %q is not locally administered", d.MAC) } if first&0x01 != 0 { t.Errorf("MAC %q is a multicast address", d.MAC) } } } func TestDevicePoolIsUsable(t *testing.T) { var pool []poolEntry if err := json.Unmarshal(devicePoolJSON, &pool); err != nil { t.Fatalf("device_pool.json is not valid JSON: %v", err) } if len(pool) < 2 { t.Fatalf("device pool has %d entries; a pool of one defeats the point", len(pool)) } for i, e := range pool { if len(e.TACPrefix) != 8 { t.Errorf("entry %d: TAC prefix %q is not 8 digits", i, e.TACPrefix) } if len(e.SDKOptions) == 0 || len(e.SDKOptions) != len(e.OSOptions) { t.Errorf("entry %d: sdk_options and os_options must pair up (%d vs %d)", i, len(e.SDKOptions), len(e.OSOptions)) } } } func TestLuhn(t *testing.T) { // Known-good IMEIs; the 15th digit must be what luhn derives from the first 14. for _, imei := range []string{"490154203237518", "356938035643809"} { if got, want := luhn(imei[:14]), string(imei[14]); got != want { t.Errorf("luhn(%s) = %s, want %s", imei[:14], got, want) } } }