Как генерировать UUID, которые могут работать с test.check в Clojure
Генеративное тестирование кажется интересным, но мне нужно было генерировать случайные UUID в рамках тестирования. java.util.UUID/newRandom не очень подходит для сжатия test.check.
Код Java выглядит следующим образом:
public static UUID randomUUID()
{
long lsb = r.nextLong();
long msb = r.nextLong();
lsb &= 0x3FFFFFFFFFFFFFFFL;
lsb |= 0x8000000000000000L; // set top two bits to variant 2
msb &= 0xFFFFFFFFFFFF0FFFL;
msb |= 0x4000; // Version 4;
return new UUID( msb, lsb );
}
Что сложнее перевести на Clojure, чем кажется.
Как мне написать случайную функцию UUID в Clojure, которая может быть успешно уменьшена?
2 ответа
Fn, который берет два long и генерирует правильный UUID типа 4:
(defn make-uuid [[msb lsb]]
(java.util.UUID. (-> msb
(bit-clear 15)
(bit-set 14)
(bit-clear 13)
(bit-clear 12))
(-> lsb
(bit-set 63)
(bit-clear 62))))
Вы можете использовать регулярное выражение для проверки результата (сначала нужно преобразовать его в строку).
(def uuid-v4-regex
#"(?i)[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[98ab][a-f0-9]{3}-[a-f0-9]{12}")
Затем вы можете проверить это следующим образом:
(def uuids (gen/fmap make-uuid (gen/tuple (gen/choose 0 Long/MAX_VALUE)
(gen/choose 0 Long/MAX_VALUE))))
(defspec check-random-uuid 100000
(for-all [uuid uuids]
(re-find uuid-v4-regex (str uuid))))
И тесты выглядят так:
(check-random-uuid)
=> {:result true, :num-tests 100000, :seed 1422050154338}
Ради интереса я удалил один из допустимых символов (9) для второго поля, и именно так выглядит провальный тест, чтобы вы могли увидеть, как может помочь сокращение от: fail to: smalllest.
(pp/pprint (check-random-uuid))
{:result nil,
:seed 1422050276824,
:failing-size 2,
:num-tests 3,
:fail [#uuid "2c6d1442-eec3-4800-972e-02905c1b3c00"],
:shrunk
{:total-nodes-visited 932,
:depth 29,
:result nil,
:smallest [#uuid "00000000-0000-4000-9000-000000000000"]}}
Который показывает, сколько шумоподавления можно удалить из вашего теста.
Начиная с версии test.check 0.9.0
есть встроенный gen/uuid
который генерирует случайные uuids, которые не сжимаются.
Если вы действительно хотите уменьшить UUID, то метод generate-two-longs также будет проще, так как новый gen/large-integer
будет генерировать полный диапазон длин, но не с равномерным распределением.
Все еще нет встроенного генератора, который мог бы генерировать равномерное распределение по всем длинным, но я думаю, что это то, что должно быть добавлено в будущем.