<commit_before>(ns metabase.models.revision-test
  (:require [expectations :refer :all]
            [korma.core :refer [table]]
            [medley.core :as m]
            [metabase.db :as db]
            (metabase.models [card :refer [Card]]
                             [interface :refer [defentity]]
                             [revision :refer :all])
            [metabase.test.data.users :refer :all]
            [metabase.util :as u]))

(defn fake-card [& {:as kwargs}]
  (m/mapply db/ins Card (merge {:name (str (java.util.UUID/randomUUID))
                                :display                :table
                                :public_perms           0
                                :dataset_query          {}
                                :visualization_settings 0
                                :creator_id             (user->id :rasta)}
                               kwargs)))

(defmacro with-fake-card [[binding & [options]] & body]
  `(let [card# (fake-card ~@(flatten (seq options)))
         ~binding card#]
     (try
       ~@body
       (finally
         (db/cascade-delete Card :id (:id card#))))))

(def ^:private reverted-to
  (atom nil))

(defentity ^:private FakedCard
  [(table :report_card)])

(extend-type FakedCardEntity
  IRevisioned
  (serialize-instance [_ _ obj]
    (assoc obj :serialized true))
  (revert-to-revision [_ _ serialized-instance]
    (reset! reverted-to (dissoc serialized-instance :serialized)))
  (describe-diff [_ _ o1 o2]
    {:before o1
     :after o2}))

(defn- push-fake-revision [card-id & {:as object}]
  (push-revision :entity FakedCard, :id card-id, :user-id (user->id :rasta), :object object))


;;; # REVISIONS + PUSH-REVISION

;; Test that a newly created Card doesn't have any revisions
(expect []
  (with-fake-card [{card-id :id}]
    (revisions FakedCard card-id)))

;; Test that when we can add a revision
(expect [{:model        "FakedCard"
          :user_id      (user->id :rasta)
          :object       {:name "Tips Created by Day", :serialized true}
          :is_reversion false}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (->> (revisions FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))

;; Test that revisions are sorted in reverse chronological order
(expect [{:model        "FakedCard"
          :user_id      (user->id :rasta)
          :object       {:name "Spots Created by Day", :serialized true}
          :is_reversion false}
         {:model        "FakedCard"
          :user_id      (user->id :rasta)
          :object       {:name "Tips Created by Day", :serialized true}
          :is_reversion false}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (push-fake-revision card-id, :name "Spots Created by Day")
    (->> (revisions FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))

;; Check that old revisions get deleted
(expect max-revisions
  (with-fake-card [{card-id :id}]
    ;; e.g. if max-revisions is 15 then insert 16 revisions
    (dorun (repeatedly (inc max-revisions) #(push-fake-revision card-id, :name "Tips Created by Day")))
    (count (revisions FakedCard card-id))))


;;; # REVISIONS+DETAILS

;; Check that revisions+details pulls in user info and adds description
(expect [{:is_reversion false,
          :user         {:id (user->id :rasta), :common_name "Rasta Toucan", :first_name "Rasta", :last_name "Toucan"},
          :description  "First revision."}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (->> (revisions+details FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))

;; Check that revisions properly defer to describe-diff
(expect [{:is_reversion false,
          :user         {:id (user->id :rasta), :common_name "<NAME>", :first_name "Rasta", :last_name "Toucan"},
          :description  {:before {:name "Tips Created by Day", :serialized true}
                         :after  {:name "Spots Created by Day", :serialized true}}}
         {:is_reversion false,
          :user         {:id (user->id :rasta), :common_name "<NAME>", :first_name "Rasta", :last_name "Toucan"},
          :description  "First revision."}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (push-fake-revision card-id, :name "Spots Created by Day")
    (->> (revisions+details FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))<commit_msg>fix the last remaining unit test failure.<commit_after>(ns metabase.models.revision-test
  (:require [expectations :refer :all]
            [korma.core :refer [table]]
            [medley.core :as m]
            [metabase.db :as db]
            (metabase.models [card :refer [Card]]
                             [interface :refer [defentity]]
                             [revision :refer :all])
            [metabase.test.data.users :refer :all]
            [metabase.util :as u]))

(defn fake-card [& {:as kwargs}]
  (m/mapply db/ins Card (merge {:name (str (java.util.UUID/randomUUID))
                                :display                :table
                                :public_perms           0
                                :dataset_query          {}
                                :visualization_settings 0
                                :creator_id             (user->id :rasta)}
                               kwargs)))

(defmacro with-fake-card [[binding & [options]] & body]
  `(let [card# (fake-card ~@(flatten (seq options)))
         ~binding card#]
     (try
       ~@body
       (finally
         (db/cascade-delete Card :id (:id card#))))))

(def ^:private reverted-to
  (atom nil))

(defentity ^:private FakedCard
  [(table :report_card)])

(extend-type FakedCardEntity
  IRevisioned
  (serialize-instance [_ _ obj]
    (assoc obj :serialized true))
  (revert-to-revision [_ _ serialized-instance]
    (reset! reverted-to (dissoc serialized-instance :serialized)))
  (describe-diff [_ o1 o2]
    (str "BEFORE=" o1 ",AFTER=" o2)))

(defn- push-fake-revision [card-id & {:as object}]
  (push-revision :entity FakedCard, :id card-id, :user-id (user->id :rasta), :object object))


;;; # REVISIONS + PUSH-REVISION

;; Test that a newly created Card doesn't have any revisions
(expect []
  (with-fake-card [{card-id :id}]
    (revisions FakedCard card-id)))

;; Test that when we can add a revision
(expect [{:model        "FakedCard"
          :user_id      (user->id :rasta)
          :object       {:name "Tips Created by Day", :serialized true}
          :is_reversion false}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (->> (revisions FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))

;; Test that revisions are sorted in reverse chronological order
(expect [{:model        "FakedCard"
          :user_id      (user->id :rasta)
          :object       {:name "Spots Created by Day", :serialized true}
          :is_reversion false}
         {:model        "FakedCard"
          :user_id      (user->id :rasta)
          :object       {:name "Tips Created by Day", :serialized true}
          :is_reversion false}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (push-fake-revision card-id, :name "Spots Created by Day")
    (->> (revisions FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))

;; Check that old revisions get deleted
(expect max-revisions
  (with-fake-card [{card-id :id}]
    ;; e.g. if max-revisions is 15 then insert 16 revisions
    (dorun (repeatedly (inc max-revisions) #(push-fake-revision card-id, :name "Tips Created by Day")))
    (count (revisions FakedCard card-id))))


;;; # REVISIONS+DETAILS

;; Check that revisions+details pulls in user info and adds description
(expect [{:is_reversion false,
          :user         {:id (user->id :rasta), :common_name "Rasta Toucan", :first_name "Rasta", :last_name "Toucan"},
          :description  "First revision."}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (->> (revisions+details FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))

;; Check that revisions properly defer to describe-diff
(expect [{:is_reversion false,
          :user         {:id (user->id :rasta), :common_name "R<NAME>can", :first_name "Rasta", :last_name "Toucan"},
          :description  "BEFORE={:name \"Tips Created by Day\", :serialized true},AFTER={:name \"Spots Created by Day\", :serialized true}"}
         {:is_reversion false,
          :user         {:id (user->id :rasta), :common_name "Rasta Toucan", :first_name "Rasta", :last_name "Toucan"},
          :description  "First revision."}]
  (with-fake-card [{card-id :id}]
    (push-fake-revision card-id, :name "Tips Created by Day")
    (push-fake-revision card-id, :name "Spots Created by Day")
    (->> (revisions+details FakedCard card-id)
         (map (u/rpartial dissoc :timestamp :id :model_id)))))
{'fraction_non_alphanumeric': 0.1415073848827107, 'fraction_numerical': 0.002172024326672459, 'mean_word_length': 2.359722728931047, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '960969', 'n_tokens_mistral': 3022, 'n_tokens_neox': 2928, 'n_words': 824}