graph_parser_test.cljs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. (ns logseq.graph-parser-test
  2. (:require [cljs.test :refer [deftest testing is are]]
  3. [clojure.string :as string]
  4. [logseq.graph-parser :as graph-parser]
  5. [logseq.db :as ldb]
  6. [logseq.graph-parser.block :as gp-block]
  7. [logseq.graph-parser.property :as gp-property]
  8. [datascript.core :as d]))
  9. (deftest parse-file
  10. (testing "id properties"
  11. (let [conn (ldb/start-conn)]
  12. (graph-parser/parse-file conn "foo.md" "- id:: 628953c1-8d75-49fe-a648-f4c612109098" {})
  13. (is (= [{:id "628953c1-8d75-49fe-a648-f4c612109098"}]
  14. (->> (d/q '[:find (pull ?b [*])
  15. :in $
  16. :where [?b :block/content] [(missing? $ ?b :block/name)]]
  17. @conn)
  18. (map first)
  19. (map :block/properties)))
  20. "id as text has correct :block/properties"))
  21. (let [conn (ldb/start-conn)]
  22. (graph-parser/parse-file conn "foo.md" "- id:: [[628953c1-8d75-49fe-a648-f4c612109098]]" {})
  23. (is (= [{:id #{"628953c1-8d75-49fe-a648-f4c612109098"}}]
  24. (->> (d/q '[:find (pull ?b [*])
  25. :in $
  26. :where [?b :block/content] [(missing? $ ?b :block/name)]]
  27. @conn)
  28. (map first)
  29. (map :block/properties)))
  30. "id as linked ref has correct :block/properties")))
  31. (testing "unexpected failure during block extraction"
  32. (let [conn (ldb/start-conn)
  33. deleted-page (atom nil)]
  34. (with-redefs [gp-block/with-pre-block-if-exists (fn stub-failure [& _args]
  35. (throw (js/Error "Testing unexpected failure")))]
  36. (try
  37. (graph-parser/parse-file conn "foo.md" "- id:: 628953c1-8d75-49fe-a648-f4c612109098"
  38. {:delete-blocks-fn (fn [page _file]
  39. (reset! deleted-page page))})
  40. (catch :default _)))
  41. (is (= nil @deleted-page)
  42. "Page should not be deleted when there is unexpected failure"))))
  43. (defn- test-property-order [num-properties]
  44. (let [conn (ldb/start-conn)
  45. properties (mapv #(keyword (str "p" %)) (range 0 num-properties))
  46. text (->> properties
  47. (map #(str (name %) ":: " (name %) "-value"))
  48. (string/join "\n"))
  49. ;; Test page properties and block properties
  50. body (str text "\n- " text)
  51. _ (graph-parser/parse-file conn "foo.md" body {})
  52. properties-orders (->> (d/q '[:find (pull ?b [*])
  53. :in $
  54. :where [?b :block/content] [(missing? $ ?b :block/name)]]
  55. @conn)
  56. (map first)
  57. (map :block/properties-order))]
  58. (is (every? vector? properties-orders)
  59. "Order is persisted as a vec to avoid edn serialization quirks")
  60. (is (= [properties properties] properties-orders)
  61. "Property order")))
  62. (deftest properties-order
  63. (testing "Sort order and persistence of a few properties"
  64. (test-property-order 4))
  65. (testing "Sort order and persistence of 10 properties"
  66. (test-property-order 10)))
  67. (defn- quoted-property-values-test
  68. [user-config]
  69. (let [conn (ldb/start-conn)
  70. _ (graph-parser/parse-file conn
  71. "foo.md"
  72. "- desc:: \"#foo is not a ref\""
  73. {:extract-options {:user-config user-config}})
  74. block (->> (d/q '[:find (pull ?b [* {:block/refs [*]}])
  75. :in $
  76. :where [?b :block/properties]]
  77. @conn)
  78. (map first)
  79. first)]
  80. (is (= {:desc "\"#foo is not a ref\""}
  81. (:block/properties block))
  82. "Quoted value is unparsed")
  83. (is (= ["desc"]
  84. (map :block/original-name (:block/refs block)))
  85. "No refs from property value")))
  86. (deftest quoted-property-values
  87. (testing "With default config"
  88. (quoted-property-values-test {}))
  89. (testing "With :rich-property-values config"
  90. (quoted-property-values-test {:rich-property-values? true})))
  91. (deftest page-properties-persistence
  92. (testing "Non-string property values"
  93. (let [conn (ldb/start-conn)]
  94. (graph-parser/parse-file conn
  95. "lythe-of-heaven.md"
  96. "rating:: 8\nrecommend:: true\narchive:: false"
  97. {})
  98. (is (= {:rating 8 :recommend true :archive false}
  99. (->> (d/q '[:find (pull ?b [*])
  100. :in $
  101. :where [?b :block/properties]]
  102. @conn)
  103. (map (comp :block/properties first))
  104. first)))))
  105. (testing "Linkable built-in properties"
  106. (let [conn (ldb/start-conn)
  107. _ (graph-parser/parse-file conn
  108. "lol.md"
  109. "alias:: 233\ntags:: fun, facts"
  110. {})
  111. block (->> (d/q '[:find (pull ?b [:block/properties {:block/alias [:block/name]} {:block/tags [:block/name]}])
  112. :in $
  113. :where [?b :block/name "lol"]]
  114. @conn)
  115. (map first)
  116. first)]
  117. (is (= {:block/alias [{:block/name "233"}]
  118. :block/tags [{:block/name "fun"} {:block/name "facts"}]
  119. :block/properties {:alias ["233"] :tags ["fun" "facts"]}}
  120. block))
  121. (is (every? vector? (vals (:block/properties block)))
  122. "Linked built-in property values as vectors provides for easier transforms"))))
  123. (defn- property-relationships-test
  124. "Runs tests on page properties and block properties. file-properties is what is
  125. visible in a file and db-properties is what is pulled out from the db"
  126. [file-properties db-properties user-config]
  127. (let [conn (ldb/start-conn)
  128. page-content (gp-property/->block-content file-properties)
  129. ;; Create Block properties from given page ones
  130. block-property-transform (fn [m] (update-keys m #(keyword (str "block-" (name %)))))
  131. block-content (gp-property/->block-content (block-property-transform file-properties))
  132. _ (graph-parser/parse-file conn
  133. "property-relationships.md"
  134. (str page-content "\n- " block-content)
  135. {:extract-options {:user-config user-config}})
  136. pages (->> (d/q '[:find (pull ?b [* :block/properties])
  137. :in $
  138. :where [?b :block/name] [?b :block/properties]]
  139. @conn)
  140. (map first))
  141. _ (assert (= 1 (count pages)))
  142. blocks (->> (d/q '[:find (pull ?b [:block/pre-block? :block/properties
  143. {:block/refs [:block/original-name]}])
  144. :in $
  145. :where [?b :block/properties] [(missing? $ ?b :block/name)]]
  146. @conn)
  147. (map first)
  148. (map (fn [m] (update m :block/refs #(map :block/original-name %)))))
  149. block-db-properties (block-property-transform db-properties)]
  150. (is (= db-properties (:block/properties (first pages)))
  151. "page has expected properties")
  152. (is (= [true nil] (map :block/pre-block? blocks))
  153. "page has 2 blocks, one of which is a pre-block")
  154. (is (= [db-properties block-db-properties]
  155. (map :block/properties blocks))
  156. "pre-block/page and block have expected properties")
  157. ;; has expected refs
  158. (are [db-props refs]
  159. (= (->> (vals db-props)
  160. ;; ignore string values
  161. (mapcat #(if (coll? %) % []))
  162. (concat (map name (keys db-props)))
  163. set)
  164. (set refs))
  165. ; pre-block/page has expected refs
  166. db-properties (first (map :block/refs blocks))
  167. ;; block has expected refs
  168. block-db-properties (second (map :block/refs blocks)))))
  169. (deftest property-relationships
  170. (let [properties {:single-link "[[bar]]"
  171. :multi-link "[[Logseq]] is the fastest #triples #[[text editor]]"
  172. :desc "This is a multiple sentence description. It has one [[link]]"
  173. :comma-prop "one, two,three"}]
  174. (testing "With default config"
  175. (property-relationships-test
  176. properties
  177. {:single-link #{"bar"}
  178. :multi-link #{"Logseq" "is the fastest" "triples" "text editor"}
  179. :desc #{"This is a multiple sentence description. It has one" "link"}
  180. :comma-prop #{"one" "two" "three"}}
  181. {}))
  182. (testing "With :rich-property-values config"
  183. (property-relationships-test
  184. properties
  185. {:single-link #{"bar"}
  186. :multi-link #{"Logseq" "triples" "text editor"}
  187. :desc #{"link"}
  188. :comma-prop "one, two,three"}
  189. {:rich-property-values? true}))))
  190. (deftest invalid-properties
  191. (let [conn (ldb/start-conn)
  192. properties {"foo" "valid"
  193. "[[foo]]" "invalid"
  194. "some,prop" "invalid"}]
  195. (graph-parser/parse-file conn "foo.md" (gp-property/->block-content properties) {})
  196. (is (= [{:block/properties {:foo "valid"}
  197. :block/invalid-properties #{"[[foo]]" "some,prop"}}]
  198. (->> (d/q '[:find (pull ?b [*])
  199. :in $
  200. :where [?b :block/properties] [(missing? $ ?b :block/name)]]
  201. @conn)
  202. (map first)
  203. (map #(select-keys % [:block/properties :block/invalid-properties]))))
  204. "Has correct (in)valid block properties")))