create-dubhe 1.2.0-pre.98 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +16 -16
  4. package/templates/101/sui-template/docker-compose.testnet.yml +73 -0
  5. package/templates/101/sui-template/packages/client/src/app/page.tsx +545 -41
  6. package/templates/101/sui-template/packages/client/src/app/providers.tsx +12 -4
  7. package/templates/101/sui-template/packages/contracts/Pub.localnet.toml +4 -4
  8. package/templates/101/sui-template/packages/contracts/counter.lock.json +20 -0
  9. package/templates/101/sui-template/packages/contracts/deployment.ts +8 -3
  10. package/templates/101/sui-template/packages/contracts/dubhe.config.json +59 -13
  11. package/templates/101/sui-template/packages/contracts/dubhe.config.ts +1 -4
  12. package/templates/101/sui-template/packages/contracts/metadata.json +1015 -68
  13. package/templates/101/sui-template/packages/contracts/package.json +7 -4
  14. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/dapp_key.move +45 -31
  15. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/error.move +8 -0
  16. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/genesis.move +30 -13
  17. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/init_test.move +19 -14
  18. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter2.move +198 -0
  19. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter2withkey.move +90 -0
  20. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/resources/value.move +30 -20
  21. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/user_storage_init.move +26 -0
  22. package/templates/101/sui-template/packages/contracts/src/counter/sources/scripts/deploy_hook.move +6 -11
  23. package/templates/101/sui-template/packages/contracts/src/counter/sources/systems/counter.move +23 -11
  24. package/templates/101/sui-template/packages/contracts/src/counter/sources/tests/counter.move +15 -14
  25. package/templates/101/sui-template/packages/contracts/src/dubhe/Move.lock +33 -30
  26. package/templates/101/sui-template/packages/contracts/src/dubhe/Move.toml +8 -3
  27. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/dapp_key.move +45 -31
  28. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/error.move +170 -0
  29. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/genesis.move +16 -13
  30. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/init_test.move +8 -14
  31. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/account_key.move +1 -3
  32. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/dapp_service.move +1776 -137
  33. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/data_key.move +1 -20
  34. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/events.move +864 -25
  35. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/scripts/deploy_hook.move +15 -16
  36. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/scripts/migrate.move +0 -3
  37. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/address_system.move +25 -17
  38. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/dapp_system.move +2802 -343
  39. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/utils.move +1 -1
  40. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/address.move +173 -55
  41. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/dapp_test.move +769 -0
  42. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/fee_test.move +2965 -0
  43. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/integration_test.move +303 -0
  44. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/listing_test.move +1422 -0
  45. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/scene_session_test.move +269 -0
  46. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/session_test.move +624 -0
  47. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/storage_test.move +700 -0
  48. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/typed_object_test.move +177 -0
  49. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/typed_scene_test.move +452 -0
  50. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/user_storage_test.move +160 -0
  51. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/utils/math.move +4 -3
  52. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/utils/type_info.move +2 -2
  53. package/templates/contract/sui-template/dubhe.config.ts +0 -1
  54. package/templates/contract/sui-template/package.json +3 -3
  55. package/templates/contract/sui-template/src/dubhe/Move.lock +33 -30
  56. package/templates/contract/sui-template/src/dubhe/Move.toml +8 -3
  57. package/templates/contract/sui-template/src/dubhe/sources/codegen/dapp_key.move +45 -31
  58. package/templates/contract/sui-template/src/dubhe/sources/codegen/error.move +170 -0
  59. package/templates/contract/sui-template/src/dubhe/sources/codegen/genesis.move +16 -13
  60. package/templates/contract/sui-template/src/dubhe/sources/codegen/init_test.move +8 -14
  61. package/templates/contract/sui-template/src/dubhe/sources/core/account_key.move +1 -3
  62. package/templates/contract/sui-template/src/dubhe/sources/core/dapp_service.move +1776 -137
  63. package/templates/contract/sui-template/src/dubhe/sources/core/data_key.move +1 -20
  64. package/templates/contract/sui-template/src/dubhe/sources/core/events.move +864 -25
  65. package/templates/contract/sui-template/src/dubhe/sources/scripts/deploy_hook.move +15 -16
  66. package/templates/contract/sui-template/src/dubhe/sources/scripts/migrate.move +0 -3
  67. package/templates/contract/sui-template/src/dubhe/sources/systems/address_system.move +25 -17
  68. package/templates/contract/sui-template/src/dubhe/sources/systems/dapp_system.move +2802 -343
  69. package/templates/contract/sui-template/src/dubhe/sources/systems/utils.move +1 -1
  70. package/templates/contract/sui-template/src/dubhe/sources/tests/address.move +173 -55
  71. package/templates/contract/sui-template/src/dubhe/sources/tests/dapp_test.move +769 -0
  72. package/templates/contract/sui-template/src/dubhe/sources/tests/fee_test.move +2965 -0
  73. package/templates/contract/sui-template/src/dubhe/sources/tests/integration_test.move +303 -0
  74. package/templates/contract/sui-template/src/dubhe/sources/tests/listing_test.move +1422 -0
  75. package/templates/contract/sui-template/src/dubhe/sources/tests/scene_session_test.move +269 -0
  76. package/templates/contract/sui-template/src/dubhe/sources/tests/session_test.move +624 -0
  77. package/templates/contract/sui-template/src/dubhe/sources/tests/storage_test.move +700 -0
  78. package/templates/contract/sui-template/src/dubhe/sources/tests/typed_object_test.move +177 -0
  79. package/templates/contract/sui-template/src/dubhe/sources/tests/typed_scene_test.move +452 -0
  80. package/templates/contract/sui-template/src/dubhe/sources/tests/user_storage_test.move +160 -0
  81. package/templates/contract/sui-template/src/dubhe/sources/utils/math.move +4 -3
  82. package/templates/contract/sui-template/src/dubhe/sources/utils/type_info.move +2 -2
  83. package/templates/contract/sui-template/src/template/Move.toml +12 -0
  84. package/templates/contract/sui-template/src/template/sources/codegen/dapp_key.move +47 -0
  85. package/templates/contract/sui-template/src/template/sources/codegen/genesis.move +34 -0
  86. package/templates/contract/sui-template/src/template/sources/codegen/init_test.move +23 -0
  87. package/templates/contract/sui-template/src/template/sources/codegen/user_storage_init.move +27 -0
  88. package/templates/contract/sui-template/src/template/sources/scripts/deploy_hook.move +13 -0
  89. package/templates/contract/sui-template/src/template/sources/scripts/migrate.move +7 -0
  90. package/templates/nextjs/sui-card-duel/.gitignore_ +51 -0
  91. package/templates/nextjs/sui-card-duel/README.md +213 -0
  92. package/templates/nextjs/sui-card-duel/docker-compose.yml +34 -0
  93. package/templates/nextjs/sui-card-duel/mprocs.yaml +17 -0
  94. package/templates/nextjs/sui-card-duel/package.json +43 -0
  95. package/templates/nextjs/sui-card-duel/packages/client/.gitignore_ +48 -0
  96. package/templates/nextjs/sui-card-duel/packages/client/.prettierignore +1 -0
  97. package/templates/nextjs/sui-card-duel/packages/client/.prettierrc.json +8 -0
  98. package/templates/nextjs/sui-card-duel/packages/client/eslint.config.mjs +22 -0
  99. package/templates/nextjs/sui-card-duel/packages/client/next.config.mjs +8 -0
  100. package/templates/nextjs/sui-card-duel/packages/client/package.json +47 -0
  101. package/templates/nextjs/sui-card-duel/packages/client/postcss.config.mjs +8 -0
  102. package/templates/nextjs/sui-card-duel/packages/client/src/app/admin/ArenaPanel.tsx +307 -0
  103. package/templates/nextjs/sui-card-duel/packages/client/src/app/admin/page.tsx +622 -0
  104. package/templates/nextjs/sui-card-duel/packages/client/src/app/brawl/[id]/page.tsx +559 -0
  105. package/templates/nextjs/sui-card-duel/packages/client/src/app/collection/page.tsx +202 -0
  106. package/templates/nextjs/sui-card-duel/packages/client/src/app/components/CardView.tsx +66 -0
  107. package/templates/nextjs/sui-card-duel/packages/client/src/app/components/GameShell.tsx +294 -0
  108. package/templates/nextjs/sui-card-duel/packages/client/src/app/components/icons.tsx +101 -0
  109. package/templates/nextjs/sui-card-duel/packages/client/src/app/duel/[id]/page.tsx +477 -0
  110. package/templates/nextjs/sui-card-duel/packages/client/src/app/favicon.ico +0 -0
  111. package/templates/nextjs/sui-card-duel/packages/client/src/app/globals.css +85 -0
  112. package/templates/nextjs/sui-card-duel/packages/client/src/app/hooks/useGame.ts +313 -0
  113. package/templates/nextjs/sui-card-duel/packages/client/src/app/layout.tsx +24 -0
  114. package/templates/nextjs/sui-card-duel/packages/client/src/app/leaderboard/page.tsx +123 -0
  115. package/templates/nextjs/sui-card-duel/packages/client/src/app/lib/game.ts +77 -0
  116. package/templates/nextjs/sui-card-duel/packages/client/src/app/lib/scenes.ts +226 -0
  117. package/templates/nextjs/sui-card-duel/packages/client/src/app/market/page.tsx +418 -0
  118. package/templates/nextjs/sui-card-duel/packages/client/src/app/page.tsx +427 -0
  119. package/templates/nextjs/sui-card-duel/packages/client/src/app/providers.tsx +69 -0
  120. package/templates/nextjs/sui-card-duel/packages/client/tailwind.config.ts +21 -0
  121. package/templates/nextjs/sui-card-duel/packages/client/tsconfig.json +30 -0
  122. package/templates/nextjs/sui-card-duel/packages/contracts/.gitignore_ +51 -0
  123. package/templates/nextjs/sui-card-duel/packages/contracts/.prettierignore +1 -0
  124. package/templates/nextjs/sui-card-duel/packages/contracts/.prettierrc.json +8 -0
  125. package/templates/nextjs/sui-card-duel/packages/contracts/Dockerfile +5 -0
  126. package/templates/nextjs/sui-card-duel/packages/contracts/Pub.localnet.toml +13 -0
  127. package/templates/nextjs/sui-card-duel/packages/contracts/card_duel.lock.json +66 -0
  128. package/templates/nextjs/sui-card-duel/packages/contracts/docker-compose.yml +34 -0
  129. package/templates/nextjs/sui-card-duel/packages/contracts/dubhe.config.ts +150 -0
  130. package/templates/nextjs/sui-card-duel/packages/contracts/logs/combined.log +31383 -0
  131. package/templates/nextjs/sui-card-duel/packages/contracts/package.json +49 -0
  132. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/config.ts +17 -0
  133. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-brawl.ts +270 -0
  134. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-duel.ts +272 -0
  135. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-lobby.ts +177 -0
  136. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-market.ts +219 -0
  137. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-session.ts +342 -0
  138. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/query-dapp-revenue.ts +95 -0
  139. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/seed.ts +92 -0
  140. package/templates/nextjs/sui-card-duel/packages/contracts/scripts/withdraw-dapp-revenue.ts +56 -0
  141. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/Move.toml +15 -0
  142. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/dapp_key.move +46 -0
  143. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/enums/card_kind.move +47 -0
  144. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/enums/match_state.move +37 -0
  145. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/enums/rarity.move +37 -0
  146. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/error.move +126 -0
  147. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/genesis.move +33 -0
  148. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/init_test.move +23 -0
  149. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/objects/arena.move +137 -0
  150. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/permits/brawl_permit.move +125 -0
  151. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/permits/duel_permit.move +125 -0
  152. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/battle_state.move +255 -0
  153. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/card.move +282 -0
  154. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/deck.move +64 -0
  155. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/game_config.move +267 -0
  156. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/gold.move +205 -0
  157. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/profile.move +255 -0
  158. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/scenes/brawl.move +313 -0
  159. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/scenes/duel.move +313 -0
  160. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/user_storage_init.move +26 -0
  161. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/scripts/deploy_hook.move +32 -0
  162. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/scripts/migrate.move +7 -0
  163. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/arena_system.move +57 -0
  164. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/brawl_system.move +559 -0
  165. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/card_system.move +146 -0
  166. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/duel_system.move +515 -0
  167. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/market_system.move +115 -0
  168. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/player_system.move +37 -0
  169. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/tests/brawl_tests.move +385 -0
  170. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/tests/duel_tests.move +656 -0
  171. package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/tests/test_helpers.move +31 -0
  172. package/templates/nextjs/sui-card-duel/packages/contracts/sui-indexer-schema.graphql +5973 -0
  173. package/templates/nextjs/sui-card-duel/pnpm-workspace.yaml +2 -0
  174. package/templates/nextjs/sui-farm/.gitignore_ +51 -0
  175. package/templates/nextjs/sui-farm/README.md +15 -0
  176. package/templates/nextjs/sui-farm/UPGRADE_NOTES.md +97 -0
  177. package/templates/nextjs/sui-farm/docker-compose.yml +34 -0
  178. package/templates/nextjs/sui-farm/mprocs.yaml +17 -0
  179. package/templates/nextjs/sui-farm/package.json +43 -0
  180. package/templates/nextjs/sui-farm/packages/client/.gitignore_ +48 -0
  181. package/templates/nextjs/sui-farm/packages/client/.prettierignore +1 -0
  182. package/templates/nextjs/sui-farm/packages/client/.prettierrc.json +8 -0
  183. package/templates/nextjs/sui-farm/packages/client/eslint.config.mjs +22 -0
  184. package/templates/nextjs/sui-farm/packages/client/next.config.mjs +8 -0
  185. package/templates/nextjs/sui-farm/packages/client/package.json +47 -0
  186. package/templates/nextjs/sui-farm/packages/client/postcss.config.mjs +8 -0
  187. package/templates/nextjs/sui-farm/packages/client/src/app/admin/page.tsx +618 -0
  188. package/templates/nextjs/sui-farm/packages/client/src/app/components/FarmLand.tsx +526 -0
  189. package/templates/nextjs/sui-farm/packages/client/src/app/components/FarmPlotCard.tsx +215 -0
  190. package/templates/nextjs/sui-farm/packages/client/src/app/components/PetAvatar.tsx +868 -0
  191. package/templates/nextjs/sui-farm/packages/client/src/app/components/PetPanel.tsx +1360 -0
  192. package/templates/nextjs/sui-farm/packages/client/src/app/components/PlantModal.tsx +147 -0
  193. package/templates/nextjs/sui-farm/packages/client/src/app/components/ProxyCard.tsx +684 -0
  194. package/templates/nextjs/sui-farm/packages/client/src/app/components/RanchLand.tsx +822 -0
  195. package/templates/nextjs/sui-farm/packages/client/src/app/components/ResourceHUD.tsx +125 -0
  196. package/templates/nextjs/sui-farm/packages/client/src/app/components/ShopPanel.tsx +232 -0
  197. package/templates/nextjs/sui-farm/packages/client/src/app/components/icons/GameIcons.tsx +574 -0
  198. package/templates/nextjs/sui-farm/packages/client/src/app/favicon.ico +0 -0
  199. package/templates/nextjs/sui-farm/packages/client/src/app/globals.css +423 -0
  200. package/templates/nextjs/sui-farm/packages/client/src/app/hooks/useWorldPermitId.ts +66 -0
  201. package/templates/nextjs/sui-farm/packages/client/src/app/layout.tsx +23 -0
  202. package/templates/nextjs/sui-farm/packages/client/src/app/leaderboard/page.tsx +185 -0
  203. package/templates/nextjs/sui-farm/packages/client/src/app/lib/crops.ts +97 -0
  204. package/templates/nextjs/sui-farm/packages/client/src/app/market/page.tsx +763 -0
  205. package/templates/nextjs/sui-farm/packages/client/src/app/page.tsx +1173 -0
  206. package/templates/nextjs/sui-farm/packages/client/src/app/providers.tsx +69 -0
  207. package/templates/nextjs/sui-farm/packages/client/src/app/state/index.tsx +5 -0
  208. package/templates/nextjs/sui-farm/packages/client/tailwind.config.ts +25 -0
  209. package/templates/nextjs/sui-farm/packages/client/tsconfig.json +30 -0
  210. package/templates/nextjs/sui-farm/packages/contracts/.gitignore_ +51 -0
  211. package/templates/nextjs/sui-farm/packages/contracts/.prettierignore +1 -0
  212. package/templates/nextjs/sui-farm/packages/contracts/.prettierrc.json +8 -0
  213. package/templates/nextjs/sui-farm/packages/contracts/Dockerfile +5 -0
  214. package/templates/nextjs/sui-farm/packages/contracts/Pub.localnet.toml +13 -0
  215. package/templates/nextjs/sui-farm/packages/contracts/counter.lock.json +14 -0
  216. package/templates/nextjs/sui-farm/packages/contracts/docker-compose.yml +34 -0
  217. package/templates/nextjs/sui-farm/packages/contracts/dubhe.config.ts +178 -0
  218. package/templates/nextjs/sui-farm/packages/contracts/harvest.lock.json +120 -0
  219. package/templates/nextjs/sui-farm/packages/contracts/package.json +48 -0
  220. package/templates/nextjs/sui-farm/packages/contracts/scripts/config.ts +17 -0
  221. package/templates/nextjs/sui-farm/packages/contracts/scripts/query-dapp-revenue.ts +95 -0
  222. package/templates/nextjs/sui-farm/packages/contracts/scripts/read-permit.ts +72 -0
  223. package/templates/nextjs/sui-farm/packages/contracts/scripts/seed.ts +85 -0
  224. package/templates/nextjs/sui-farm/packages/contracts/scripts/withdraw-dapp-revenue.ts +56 -0
  225. package/templates/nextjs/sui-farm/packages/contracts/src/counter/Move.toml +14 -0
  226. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/dapp_key.move +31 -0
  227. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/error.move +10 -0
  228. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/genesis.move +33 -0
  229. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/init_test.move +23 -0
  230. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/resources/counter1.move +64 -0
  231. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/resources/counter2.move +70 -0
  232. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/user_storage_init.move +26 -0
  233. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/scripts/deploy_hook.move +8 -0
  234. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/scripts/migrate.move +8 -0
  235. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/systems/counter.move +13 -0
  236. package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/tests/counter.move +28 -0
  237. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/Move.toml +14 -0
  238. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/dapp_key.move +46 -0
  239. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/crop_type.move +47 -0
  240. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/egg_type.move +42 -0
  241. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/pet_rarity.move +37 -0
  242. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/pet_species.move +52 -0
  243. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/error.move +110 -0
  244. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/genesis.move +33 -0
  245. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/init_test.move +23 -0
  246. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/permits/world.move +125 -0
  247. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/carrot.move +136 -0
  248. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/carrot_seed.move +80 -0
  249. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/common_egg.move +136 -0
  250. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/corn.move +136 -0
  251. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/corn_seed.move +80 -0
  252. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/crow_charges.move +162 -0
  253. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/crow_damage.move +207 -0
  254. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/farm_plot.move +261 -0
  255. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/gold.move +80 -0
  256. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet.move +467 -0
  257. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_config.move +372 -0
  258. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_hatch.move +162 -0
  259. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_slot_index.move +83 -0
  260. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_slots.move +64 -0
  261. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/profile.move +162 -0
  262. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pumpkin.move +136 -0
  263. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pumpkin_seed.move +80 -0
  264. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/rare_egg.move +136 -0
  265. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/scarecrow.move +64 -0
  266. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/season_config.move +197 -0
  267. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/season_stats.move +64 -0
  268. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/seasonal_egg.move +136 -0
  269. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/shop_config.move +267 -0
  270. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/trophy.move +245 -0
  271. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/wheat.move +136 -0
  272. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/wheat_seed.move +80 -0
  273. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/world_permit_id.move +64 -0
  274. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/user_storage_init.move +26 -0
  275. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/scripts/deploy_hook.move +45 -0
  276. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/scripts/migrate.move +7 -0
  277. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/crow_system.move +96 -0
  278. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/farm_system.move +182 -0
  279. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/market_system.move +172 -0
  280. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/pet_system.move +495 -0
  281. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/season_system.move +70 -0
  282. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/shop_system.move +112 -0
  283. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/world_system.move +34 -0
  284. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/tests/farm_tests.move +1192 -0
  285. package/templates/nextjs/sui-farm/pnpm-workspace.yaml +2 -0
  286. package/templates/nextjs/sui-template/packages/client/src/app/components/ProxyCard.tsx +683 -0
  287. package/templates/nextjs/sui-template/packages/client/src/app/page.tsx +510 -5
  288. package/templates/nextjs/sui-template/packages/client/src/app/providers.tsx +13 -5
  289. package/templates/nextjs/sui-template/packages/contracts/Pub.localnet.toml +4 -4
  290. package/templates/nextjs/sui-template/packages/contracts/counter.lock.json +14 -0
  291. package/templates/nextjs/sui-template/packages/contracts/deployment.ts +8 -3
  292. package/templates/nextjs/sui-template/packages/contracts/dubhe.config.json +9 -9
  293. package/templates/nextjs/sui-template/packages/contracts/dubhe.config.ts +0 -4
  294. package/templates/nextjs/sui-template/packages/contracts/metadata.json +180 -124
  295. package/templates/nextjs/sui-template/packages/contracts/package.json +8 -4
  296. package/templates/nextjs/sui-template/packages/contracts/src/counter/Move.toml +4 -0
  297. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/dapp_key.move +45 -31
  298. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/error.move +10 -0
  299. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/genesis.move +30 -13
  300. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/init_test.move +19 -14
  301. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter1.move +30 -20
  302. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter2.move +35 -24
  303. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/user_storage_init.move +26 -0
  304. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/scripts/deploy_hook.move +6 -10
  305. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/systems/counter.move +7 -20
  306. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/tests/counter.move +14 -27
  307. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/Move.lock +33 -30
  308. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/Move.toml +8 -3
  309. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/dapp_key.move +45 -31
  310. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/error.move +170 -0
  311. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/genesis.move +16 -13
  312. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/init_test.move +8 -14
  313. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/account_key.move +1 -3
  314. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/dapp_service.move +1776 -137
  315. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/data_key.move +1 -20
  316. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/events.move +864 -25
  317. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/scripts/deploy_hook.move +15 -16
  318. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/scripts/migrate.move +0 -3
  319. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/address_system.move +25 -17
  320. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/dapp_system.move +2802 -343
  321. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/utils.move +1 -1
  322. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/address.move +173 -55
  323. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/dapp_test.move +769 -0
  324. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/fee_test.move +2965 -0
  325. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/integration_test.move +303 -0
  326. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/listing_test.move +1422 -0
  327. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/scene_session_test.move +269 -0
  328. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/session_test.move +624 -0
  329. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/storage_test.move +700 -0
  330. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_object_test.move +177 -0
  331. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_scene_test.move +452 -0
  332. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/user_storage_test.move +160 -0
  333. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/utils/math.move +4 -3
  334. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/utils/type_info.move +2 -2
  335. package/templates/101/sui-template/packages/contracts/src/counter/Move.lock +0 -41
  336. package/templates/101/sui-template/packages/contracts/src/counter/Published.toml +0 -9
  337. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/errors.move +0 -12
  338. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/errors.move +0 -140
  339. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
  340. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
  341. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
  342. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
  343. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/dapp_store.move +0 -29
  344. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/session_system.move +0 -44
  345. package/templates/contract/sui-template/src/dubhe/sources/codegen/errors.move +0 -140
  346. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
  347. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
  348. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
  349. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
  350. package/templates/contract/sui-template/src/dubhe/sources/core/dapp_store.move +0 -29
  351. package/templates/contract/sui-template/src/dubhe/sources/systems/session_system.move +0 -44
  352. package/templates/nextjs/sui-template/packages/contracts/src/counter/Move.lock +0 -47
  353. package/templates/nextjs/sui-template/packages/contracts/src/counter/Published.toml +0 -9
  354. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/errors.move +0 -12
  355. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/errors.move +0 -140
  356. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
  357. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
  358. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
  359. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
  360. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/dapp_store.move +0 -29
  361. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/session_system.move +0 -44
@@ -0,0 +1,1192 @@
1
+ /// Comprehensive boundary tests for harvest game systems.
2
+ ///
3
+ /// Coverage:
4
+ /// farm_system — plant (6 success + 5 failure cases)
5
+ /// — harvest (10 success + 4 failure cases)
6
+ /// shop_system — buy_seeds (5 success + 5 failure cases)
7
+ /// — buy_extra_plot (3 success + 3 failure cases)
8
+ /// — sell_crops (4 success + 4 failure cases)
9
+ /// crow_system — place_scarecrow (2 success + 2 failure cases)
10
+ ///
11
+ /// Logic checks verified:
12
+ /// • plant always deducts exactly 1 seed and stores crop_yield as plot count
13
+ /// • harvest returns base yield with no bonus, 2× season bonus (SEASON_BONUS_PCT=200),
14
+ /// 30% crow_damage debuff, expired debuff, and all three combined
15
+ /// • harvest clears the plot and updates profile.total_earned + season_stats
16
+ /// • harvest boundary: exactly at harvest_at succeeds, one ms before fails
17
+ /// • seed prices from deploy_hook: wheat=5, corn=20, carrot=60, pumpkin=40, plot=200
18
+ /// • sell prices: wheat=8, corn=35, carrot=120, pumpkin=100
19
+ /// • max plots cap: 12; starting plots: 3
20
+
21
+ #[test_only]
22
+ module harvest::farm_tests {
23
+ use sui::clock;
24
+ use dubhe::dapp_service::{DappStorage, UserStorage};
25
+ use harvest::init_test;
26
+ use harvest::deploy_hook;
27
+ use harvest::farm_system;
28
+ use harvest::shop_system;
29
+ use harvest::crow_system;
30
+ use harvest::gold;
31
+ use harvest::wheat_seed;
32
+ use harvest::corn_seed;
33
+ use harvest::carrot_seed;
34
+ use harvest::pumpkin_seed;
35
+ use harvest::wheat;
36
+ use harvest::corn;
37
+ use harvest::carrot;
38
+ use harvest::pumpkin;
39
+ use harvest::profile;
40
+ use harvest::farm_plot;
41
+ use harvest::season_config;
42
+ use harvest::season_stats;
43
+ use harvest::crow_damage;
44
+ use harvest::scarecrow;
45
+
46
+ // ─── Constants (must match farm_system.move / deploy_hook.move) ──────────────
47
+ const CROP_WHEAT: u8 = 1;
48
+ const CROP_CORN: u8 = 2;
49
+ const CROP_CARROT: u8 = 3;
50
+ const CROP_PUMPKIN: u8 = 4;
51
+
52
+ const WHEAT_MS: u64 = 60_000; // 1 min
53
+ const CORN_MS: u64 = 120_000; // 2 min
54
+ const CARROT_MS: u64 = 240_000; // 4 min
55
+ const PUMPKIN_MS: u64 = 300_000; // 5 min
56
+
57
+ const WHEAT_YIELD: u64 = 6;
58
+ const CORN_YIELD: u64 = 4;
59
+ const CARROT_YIELD: u64 = 3;
60
+ const PUMPKIN_YIELD: u64 = 3;
61
+
62
+ // sell prices used in shop_system.move
63
+ const WHEAT_SELL: u64 = 8;
64
+ const CORN_SELL: u64 = 35;
65
+ const CARROT_SELL: u64 = 120;
66
+ const PUMPKIN_SELL: u64 = 100;
67
+
68
+ // seed prices set by deploy_hook
69
+ const WHEAT_PRICE: u64 = 5;
70
+ const CORN_PRICE: u64 = 20;
71
+ const CARROT_PRICE: u64 = 60;
72
+ const PUMPKIN_PRICE: u64 = 40;
73
+ const PLOT_PRICE: u64 = 200;
74
+
75
+ const SEASON_BONUS_PCT: u64 = 200;
76
+ const CROW_DAMAGE_PCT: u8 = 30;
77
+
78
+ // ─── Test helpers ─────────────────────────────────────────────────────────────
79
+
80
+ fun setup_dapp(ctx: &mut TxContext): DappStorage {
81
+ let mut ds = init_test::create_dapp_storage_for_testing(ctx);
82
+ deploy_hook::run(&mut ds, ctx);
83
+ ds
84
+ }
85
+
86
+ /// Create a UserStorage pre-configured as a registered player.
87
+ /// Uses ctx.sender() as canonical_owner so set_record calls pass the
88
+ /// is_write_authorized check (sender == canonical_owner).
89
+ /// Sets profile (total_earned=0, plots_owned=3) and the requested gold.
90
+ fun setup_player(gold_amount: u64, ctx: &mut TxContext): UserStorage {
91
+ let owner = ctx.sender();
92
+ let mut us = init_test::create_user_storage_for_testing(owner, ctx);
93
+ gold::set(&mut us, gold_amount, ctx);
94
+ profile::set(&mut us, 0, 3, ctx);
95
+ us
96
+ }
97
+
98
+ fun give_crop(us: &mut UserStorage, crop_type: u8, amount: u64, ctx: &mut TxContext) {
99
+ if (crop_type == CROP_WHEAT) { wheat::add(us, amount, ctx) }
100
+ else if (crop_type == CROP_CORN) { corn::add(us, amount, ctx) }
101
+ else if (crop_type == CROP_CARROT) { carrot::add(us, amount, ctx) }
102
+ else { pumpkin::add(us, amount, ctx) };
103
+ }
104
+
105
+ /// Give seeds (the separate seed resource used for planting).
106
+ fun give_seed(us: &mut UserStorage, crop_type: u8, amount: u64, ctx: &mut TxContext) {
107
+ if (crop_type == CROP_WHEAT) { wheat_seed::add(us, amount, ctx) }
108
+ else if (crop_type == CROP_CORN) { corn_seed::add(us, amount, ctx) }
109
+ else if (crop_type == CROP_CARROT) { carrot_seed::add(us, amount, ctx) }
110
+ else { pumpkin_seed::add(us, amount, ctx) };
111
+ }
112
+
113
+ /// Plant a crop, advance the clock to harvest_at + extra_ms, and return the clock.
114
+ /// Caller must call clock::destroy_for_testing when done.
115
+ fun plant_then_advance(
116
+ ds: &DappStorage,
117
+ us: &mut UserStorage,
118
+ plot_id: u8,
119
+ crop_type: u8,
120
+ extra_ms: u64,
121
+ ctx: &mut TxContext,
122
+ ): clock::Clock {
123
+ let mut clk = clock::create_for_testing(ctx);
124
+ clock::set_for_testing(&mut clk, 1000);
125
+ farm_system::plant(ds, us, plot_id, crop_type, &clk, ctx);
126
+ let harvest_at = farm_plot::get_harvest_at(us, plot_id);
127
+ clock::set_for_testing(&mut clk, harvest_at + extra_ms);
128
+ clk
129
+ }
130
+
131
+ // ═════════════════════════════════════════════════════════════════════════════
132
+ // farm_system::plant
133
+ // ═════════════════════════════════════════════════════════════════════════════
134
+
135
+ // ── success cases ─────────────────────────────────────────────────────────────
136
+
137
+ #[test]
138
+ fun test_plant_wheat_deducts_one_seed_stores_yield() {
139
+ let mut ctx = sui::tx_context::dummy();
140
+ let ds = setup_dapp(&mut ctx);
141
+ let mut us = setup_player(100, &mut ctx);
142
+ give_seed(&mut us, CROP_WHEAT, 5, &mut ctx);
143
+
144
+ let mut clk = clock::create_for_testing(&mut ctx);
145
+ clock::set_for_testing(&mut clk, 1000);
146
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
147
+
148
+ assert!(wheat_seed::get(&us) == 4, 0); // 5 - 1 seed deducted
149
+ assert!(farm_plot::get_count(&us, 0) == WHEAT_YIELD, 1); // stored yield = 6
150
+ assert!(farm_plot::get_crop_type(&us, 0) == CROP_WHEAT, 2);
151
+ let planted_at = farm_plot::get_planted_at(&us, 0);
152
+ assert!(farm_plot::get_harvest_at(&us, 0) == planted_at + WHEAT_MS, 3);
153
+
154
+ clock::destroy_for_testing(clk);
155
+ std::unit_test::destroy(ds);
156
+ std::unit_test::destroy(us);
157
+ }
158
+
159
+ #[test]
160
+ fun test_plant_corn_deducts_one_seed_stores_yield() {
161
+ let mut ctx = sui::tx_context::dummy();
162
+ let ds = setup_dapp(&mut ctx);
163
+ let mut us = setup_player(100, &mut ctx);
164
+ give_seed(&mut us, CROP_CORN, 3, &mut ctx);
165
+
166
+ let mut clk = clock::create_for_testing(&mut ctx);
167
+ clock::set_for_testing(&mut clk, 1000);
168
+ farm_system::plant(&ds, &mut us, 0, CROP_CORN, &clk, &mut ctx);
169
+
170
+ assert!(corn_seed::get(&us) == 2, 0);
171
+ assert!(farm_plot::get_count(&us, 0) == CORN_YIELD, 1);
172
+ let planted_at = farm_plot::get_planted_at(&us, 0);
173
+ assert!(farm_plot::get_harvest_at(&us, 0) == planted_at + CORN_MS, 2);
174
+
175
+ clock::destroy_for_testing(clk);
176
+ std::unit_test::destroy(ds);
177
+ std::unit_test::destroy(us);
178
+ }
179
+
180
+ #[test]
181
+ fun test_plant_carrot_deducts_one_seed_stores_yield() {
182
+ let mut ctx = sui::tx_context::dummy();
183
+ let ds = setup_dapp(&mut ctx);
184
+ let mut us = setup_player(100, &mut ctx);
185
+ give_seed(&mut us, CROP_CARROT, 2, &mut ctx);
186
+
187
+ let mut clk = clock::create_for_testing(&mut ctx);
188
+ clock::set_for_testing(&mut clk, 1000);
189
+ farm_system::plant(&ds, &mut us, 0, CROP_CARROT, &clk, &mut ctx);
190
+
191
+ assert!(carrot_seed::get(&us) == 1, 0);
192
+ assert!(farm_plot::get_count(&us, 0) == CARROT_YIELD, 1);
193
+ let planted_at = farm_plot::get_planted_at(&us, 0);
194
+ assert!(farm_plot::get_harvest_at(&us, 0) == planted_at + CARROT_MS, 2);
195
+
196
+ clock::destroy_for_testing(clk);
197
+ std::unit_test::destroy(ds);
198
+ std::unit_test::destroy(us);
199
+ }
200
+
201
+ #[test]
202
+ fun test_plant_pumpkin_deducts_one_seed_stores_yield() {
203
+ let mut ctx = sui::tx_context::dummy();
204
+ let ds = setup_dapp(&mut ctx);
205
+ let mut us = setup_player(100, &mut ctx);
206
+ give_seed(&mut us, CROP_PUMPKIN, 1, &mut ctx);
207
+
208
+ let mut clk = clock::create_for_testing(&mut ctx);
209
+ clock::set_for_testing(&mut clk, 1000);
210
+ farm_system::plant(&ds, &mut us, 0, CROP_PUMPKIN, &clk, &mut ctx);
211
+
212
+ assert!(!pumpkin_seed::has(&us) || pumpkin_seed::get(&us) == 0, 0);
213
+ assert!(farm_plot::get_count(&us, 0) == PUMPKIN_YIELD, 1);
214
+ let planted_at = farm_plot::get_planted_at(&us, 0);
215
+ assert!(farm_plot::get_harvest_at(&us, 0) == planted_at + PUMPKIN_MS, 2);
216
+
217
+ clock::destroy_for_testing(clk);
218
+ std::unit_test::destroy(ds);
219
+ std::unit_test::destroy(us);
220
+ }
221
+
222
+ #[test]
223
+ fun test_plant_three_different_crops_on_three_plots() {
224
+ let mut ctx = sui::tx_context::dummy();
225
+ let ds = setup_dapp(&mut ctx);
226
+ let mut us = setup_player(100, &mut ctx);
227
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
228
+ give_seed(&mut us, CROP_CORN, 1, &mut ctx);
229
+ give_seed(&mut us, CROP_CARROT, 1, &mut ctx);
230
+
231
+ let mut clk = clock::create_for_testing(&mut ctx);
232
+ clock::set_for_testing(&mut clk, 1000);
233
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
234
+ farm_system::plant(&ds, &mut us, 1, CROP_CORN, &clk, &mut ctx);
235
+ farm_system::plant(&ds, &mut us, 2, CROP_CARROT, &clk, &mut ctx);
236
+
237
+ assert!(farm_plot::get_crop_type(&us, 0) == CROP_WHEAT, 0);
238
+ assert!(farm_plot::get_crop_type(&us, 1) == CROP_CORN, 1);
239
+ assert!(farm_plot::get_crop_type(&us, 2) == CROP_CARROT, 2);
240
+ assert!(farm_plot::get_count(&us, 0) == WHEAT_YIELD, 3);
241
+ assert!(farm_plot::get_count(&us, 1) == CORN_YIELD, 4);
242
+ assert!(farm_plot::get_count(&us, 2) == CARROT_YIELD, 5);
243
+
244
+ clock::destroy_for_testing(clk);
245
+ std::unit_test::destroy(ds);
246
+ std::unit_test::destroy(us);
247
+ }
248
+
249
+ #[test]
250
+ fun test_plant_plot_2_boundary_last_owned_plot() {
251
+ let mut ctx = sui::tx_context::dummy();
252
+ let ds = setup_dapp(&mut ctx);
253
+ let mut us = setup_player(100, &mut ctx); // plots_owned = 3 → indices 0,1,2
254
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
255
+
256
+ let mut clk = clock::create_for_testing(&mut ctx);
257
+ clock::set_for_testing(&mut clk, 1000);
258
+ farm_system::plant(&ds, &mut us, 2, CROP_WHEAT, &clk, &mut ctx); // index 2 is valid
259
+
260
+ assert!(farm_plot::get_crop_type(&us, 2) == CROP_WHEAT, 0);
261
+
262
+ clock::destroy_for_testing(clk);
263
+ std::unit_test::destroy(ds);
264
+ std::unit_test::destroy(us);
265
+ }
266
+
267
+ // ── failure cases ─────────────────────────────────────────────────────────────
268
+
269
+ #[test]
270
+ #[expected_failure]
271
+ fun test_plant_fails_not_registered() {
272
+ let mut ctx = sui::tx_context::dummy();
273
+ let ds = setup_dapp(&mut ctx);
274
+ let mut us = init_test::create_user_storage_for_testing(ctx.sender(), &mut ctx); // no profile
275
+ let clk = clock::create_for_testing(&mut ctx);
276
+
277
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
278
+
279
+ clock::destroy_for_testing(clk);
280
+ std::unit_test::destroy(ds);
281
+ std::unit_test::destroy(us);
282
+ }
283
+
284
+ #[test]
285
+ #[expected_failure]
286
+ fun test_plant_fails_crop_type_none() {
287
+ let mut ctx = sui::tx_context::dummy();
288
+ let ds = setup_dapp(&mut ctx);
289
+ let mut us = setup_player(100, &mut ctx);
290
+ let clk = clock::create_for_testing(&mut ctx);
291
+
292
+ farm_system::plant(&ds, &mut us, 0, 0, &clk, &mut ctx); // 0 = CROP_NONE
293
+
294
+ clock::destroy_for_testing(clk);
295
+ std::unit_test::destroy(ds);
296
+ std::unit_test::destroy(us);
297
+ }
298
+
299
+ #[test]
300
+ #[expected_failure]
301
+ fun test_plant_fails_crop_type_out_of_range() {
302
+ let mut ctx = sui::tx_context::dummy();
303
+ let ds = setup_dapp(&mut ctx);
304
+ let mut us = setup_player(100, &mut ctx);
305
+ let clk = clock::create_for_testing(&mut ctx);
306
+
307
+ farm_system::plant(&ds, &mut us, 0, 5, &clk, &mut ctx); // no crop type 5
308
+
309
+ clock::destroy_for_testing(clk);
310
+ std::unit_test::destroy(ds);
311
+ std::unit_test::destroy(us);
312
+ }
313
+
314
+ #[test]
315
+ #[expected_failure]
316
+ fun test_plant_fails_plot_not_owned() {
317
+ let mut ctx = sui::tx_context::dummy();
318
+ let ds = setup_dapp(&mut ctx);
319
+ let mut us = setup_player(100, &mut ctx); // plots_owned = 3 → valid: 0,1,2
320
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
321
+ let clk = clock::create_for_testing(&mut ctx);
322
+
323
+ farm_system::plant(&ds, &mut us, 3, CROP_WHEAT, &clk, &mut ctx); // index 3 not owned
324
+
325
+ clock::destroy_for_testing(clk);
326
+ std::unit_test::destroy(ds);
327
+ std::unit_test::destroy(us);
328
+ }
329
+
330
+ #[test]
331
+ #[expected_failure]
332
+ fun test_plant_fails_plot_already_has_crop() {
333
+ let mut ctx = sui::tx_context::dummy();
334
+ let ds = setup_dapp(&mut ctx);
335
+ let mut us = setup_player(100, &mut ctx);
336
+ give_seed(&mut us, CROP_WHEAT, 3, &mut ctx);
337
+ let mut clk = clock::create_for_testing(&mut ctx);
338
+ clock::set_for_testing(&mut clk, 1000);
339
+
340
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
341
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx); // second plant aborts
342
+
343
+ clock::destroy_for_testing(clk);
344
+ std::unit_test::destroy(ds);
345
+ std::unit_test::destroy(us);
346
+ }
347
+
348
+ #[test]
349
+ #[expected_failure]
350
+ fun test_plant_fails_no_seeds_in_inventory() {
351
+ let mut ctx = sui::tx_context::dummy();
352
+ let ds = setup_dapp(&mut ctx);
353
+ let mut us = setup_player(100, &mut ctx); // zero wheat
354
+ let clk = clock::create_for_testing(&mut ctx);
355
+
356
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
357
+
358
+ clock::destroy_for_testing(clk);
359
+ std::unit_test::destroy(ds);
360
+ std::unit_test::destroy(us);
361
+ }
362
+
363
+ // ═════════════════════════════════════════════════════════════════════════════
364
+ // farm_system::harvest
365
+ // ═════════════════════════════════════════════════════════════════════════════
366
+
367
+ // ── success cases ─────────────────────────────────────────────────────────────
368
+
369
+ #[test]
370
+ fun test_harvest_wheat_base_yield_no_bonus() {
371
+ let mut ctx = sui::tx_context::dummy();
372
+ let ds = setup_dapp(&mut ctx);
373
+ let mut us = setup_player(100, &mut ctx);
374
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
375
+
376
+ let clk = plant_then_advance(&ds, &mut us, 0, CROP_WHEAT, 0, &mut ctx);
377
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
378
+
379
+ assert!(wheat::get(&us) == WHEAT_YIELD, 0); // base 6
380
+ assert!(farm_plot::get_crop_type(&us, 0) == 0, 1); // plot cleared
381
+ assert!(farm_plot::get_count(&us, 0) == 0, 2);
382
+ assert!(profile::get_total_earned(&us) == WHEAT_YIELD * WHEAT_SELL, 3); // 48
383
+
384
+ clock::destroy_for_testing(clk);
385
+ std::unit_test::destroy(ds);
386
+ std::unit_test::destroy(us);
387
+ }
388
+
389
+ #[test]
390
+ fun test_harvest_corn_base_yield_no_bonus() {
391
+ let mut ctx = sui::tx_context::dummy();
392
+ let ds = setup_dapp(&mut ctx);
393
+ let mut us = setup_player(100, &mut ctx);
394
+ give_seed(&mut us, CROP_CORN, 1, &mut ctx);
395
+
396
+ let clk = plant_then_advance(&ds, &mut us, 0, CROP_CORN, 0, &mut ctx);
397
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
398
+
399
+ assert!(corn::get(&us) == CORN_YIELD, 0);
400
+ assert!(profile::get_total_earned(&us) == CORN_YIELD * CORN_SELL, 1); // 140
401
+
402
+ clock::destroy_for_testing(clk);
403
+ std::unit_test::destroy(ds);
404
+ std::unit_test::destroy(us);
405
+ }
406
+
407
+ #[test]
408
+ fun test_harvest_carrot_base_yield_no_bonus() {
409
+ let mut ctx = sui::tx_context::dummy();
410
+ let ds = setup_dapp(&mut ctx);
411
+ let mut us = setup_player(100, &mut ctx);
412
+ give_seed(&mut us, CROP_CARROT, 1, &mut ctx);
413
+
414
+ let clk = plant_then_advance(&ds, &mut us, 0, CROP_CARROT, 0, &mut ctx);
415
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
416
+
417
+ assert!(carrot::get(&us) == CARROT_YIELD, 0);
418
+ assert!(profile::get_total_earned(&us) == CARROT_YIELD * CARROT_SELL, 1); // 360
419
+
420
+ clock::destroy_for_testing(clk);
421
+ std::unit_test::destroy(ds);
422
+ std::unit_test::destroy(us);
423
+ }
424
+
425
+ #[test]
426
+ fun test_harvest_pumpkin_base_yield_no_bonus() {
427
+ let mut ctx = sui::tx_context::dummy();
428
+ let ds = setup_dapp(&mut ctx);
429
+ let mut us = setup_player(100, &mut ctx);
430
+ give_seed(&mut us, CROP_PUMPKIN, 1, &mut ctx);
431
+
432
+ let clk = plant_then_advance(&ds, &mut us, 0, CROP_PUMPKIN, 0, &mut ctx);
433
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
434
+
435
+ assert!(pumpkin::get(&us) == PUMPKIN_YIELD, 0);
436
+ assert!(profile::get_total_earned(&us) == PUMPKIN_YIELD * PUMPKIN_SELL, 1); // 300
437
+
438
+ clock::destroy_for_testing(clk);
439
+ std::unit_test::destroy(ds);
440
+ std::unit_test::destroy(us);
441
+ }
442
+
443
+ #[test]
444
+ fun test_harvest_succeeds_exactly_at_harvest_at() {
445
+ let mut ctx = sui::tx_context::dummy();
446
+ let ds = setup_dapp(&mut ctx);
447
+ let mut us = setup_player(100, &mut ctx);
448
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
449
+
450
+ // plant_then_advance with extra_ms=0 sets clock to exactly harvest_at
451
+ let clk = plant_then_advance(&ds, &mut us, 0, CROP_WHEAT, 0, &mut ctx);
452
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
453
+
454
+ assert!(wheat::get(&us) == WHEAT_YIELD, 0);
455
+
456
+ clock::destroy_for_testing(clk);
457
+ std::unit_test::destroy(ds);
458
+ std::unit_test::destroy(us);
459
+ }
460
+
461
+ #[test]
462
+ fun test_harvest_season_bonus_doubles_matching_crop() {
463
+ let mut ctx = sui::tx_context::dummy();
464
+ let mut ds = setup_dapp(&mut ctx);
465
+ let mut us = setup_player(100, &mut ctx);
466
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
467
+
468
+ let mut clk = clock::create_for_testing(&mut ctx);
469
+ clock::set_for_testing(&mut clk, 1000);
470
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
471
+
472
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
473
+ // Active season: bonus_crop = WHEAT, end far in future
474
+ season_config::set(&mut ds, 1, harvest_at + 1_000_000, CROP_WHEAT);
475
+ clock::set_for_testing(&mut clk, harvest_at);
476
+
477
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
478
+
479
+ // after_bonus = WHEAT_YIELD * SEASON_BONUS_PCT / 100 = 6 * 200 / 100 = 12
480
+ assert!(wheat::get(&us) == WHEAT_YIELD * SEASON_BONUS_PCT / 100, 0); // 12
481
+
482
+ clock::destroy_for_testing(clk);
483
+ std::unit_test::destroy(ds);
484
+ std::unit_test::destroy(us);
485
+ }
486
+
487
+ #[test]
488
+ fun test_harvest_season_bonus_no_effect_on_non_matching_crop() {
489
+ let mut ctx = sui::tx_context::dummy();
490
+ let mut ds = setup_dapp(&mut ctx);
491
+ let mut us = setup_player(100, &mut ctx);
492
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
493
+
494
+ let mut clk = clock::create_for_testing(&mut ctx);
495
+ clock::set_for_testing(&mut clk, 1000);
496
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
497
+
498
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
499
+ // Season active but bonus is CORN, not WHEAT
500
+ season_config::set(&mut ds, 1, harvest_at + 1_000_000, CROP_CORN);
501
+ clock::set_for_testing(&mut clk, harvest_at);
502
+
503
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
504
+
505
+ assert!(wheat::get(&us) == WHEAT_YIELD, 0); // no boost
506
+
507
+ clock::destroy_for_testing(clk);
508
+ std::unit_test::destroy(ds);
509
+ std::unit_test::destroy(us);
510
+ }
511
+
512
+ #[test]
513
+ fun test_harvest_expired_season_no_boost() {
514
+ let mut ctx = sui::tx_context::dummy();
515
+ let mut ds = setup_dapp(&mut ctx);
516
+ let mut us = setup_player(100, &mut ctx);
517
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
518
+
519
+ let mut clk = clock::create_for_testing(&mut ctx);
520
+ clock::set_for_testing(&mut clk, 1000);
521
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
522
+
523
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
524
+ // Season already ended 1 ms before harvest
525
+ season_config::set(&mut ds, 1, harvest_at - 1, CROP_WHEAT);
526
+ clock::set_for_testing(&mut clk, harvest_at);
527
+
528
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
529
+
530
+ assert!(wheat::get(&us) == WHEAT_YIELD, 0); // no boost (now >= season_end)
531
+
532
+ clock::destroy_for_testing(clk);
533
+ std::unit_test::destroy(ds);
534
+ std::unit_test::destroy(us);
535
+ }
536
+
537
+ #[test]
538
+ fun test_harvest_crow_damage_active_reduces_yield() {
539
+ let mut ctx = sui::tx_context::dummy();
540
+ let ds = setup_dapp(&mut ctx);
541
+ let mut us = setup_player(100, &mut ctx);
542
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
543
+
544
+ let mut clk = clock::create_for_testing(&mut ctx);
545
+ clock::set_for_testing(&mut clk, 1000);
546
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
547
+
548
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
549
+ // Crow damage 30%, expires after harvest_at
550
+ crow_damage::set(&mut us, harvest_at + 100_000, CROW_DAMAGE_PCT, &mut ctx);
551
+ clock::set_for_testing(&mut clk, harvest_at);
552
+
553
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
554
+
555
+ // final = 6 * (100 - 30) / 100 = 6 * 70 / 100 = 4
556
+ assert!(wheat::get(&us) == 4, 0);
557
+
558
+ clock::destroy_for_testing(clk);
559
+ std::unit_test::destroy(ds);
560
+ std::unit_test::destroy(us);
561
+ }
562
+
563
+ #[test]
564
+ fun test_harvest_crow_damage_expired_no_penalty() {
565
+ let mut ctx = sui::tx_context::dummy();
566
+ let ds = setup_dapp(&mut ctx);
567
+ let mut us = setup_player(100, &mut ctx);
568
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
569
+
570
+ let mut clk = clock::create_for_testing(&mut ctx);
571
+ clock::set_for_testing(&mut clk, 1000);
572
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
573
+
574
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
575
+ // Crow damage already expired 1 ms before harvest
576
+ crow_damage::set(&mut us, harvest_at - 1, CROW_DAMAGE_PCT, &mut ctx);
577
+ clock::set_for_testing(&mut clk, harvest_at);
578
+
579
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
580
+
581
+ assert!(wheat::get(&us) == WHEAT_YIELD, 0); // full yield, debuff expired
582
+
583
+ clock::destroy_for_testing(clk);
584
+ std::unit_test::destroy(ds);
585
+ std::unit_test::destroy(us);
586
+ }
587
+
588
+ #[test]
589
+ fun test_harvest_season_bonus_and_crow_damage_combined() {
590
+ let mut ctx = sui::tx_context::dummy();
591
+ let mut ds = setup_dapp(&mut ctx);
592
+ let mut us = setup_player(100, &mut ctx);
593
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
594
+
595
+ let mut clk = clock::create_for_testing(&mut ctx);
596
+ clock::set_for_testing(&mut clk, 1000);
597
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
598
+
599
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
600
+ season_config::set(&mut ds, 1, harvest_at + 1_000_000, CROP_WHEAT); // 2× bonus
601
+ crow_damage::set(&mut us, harvest_at + 1_000_000, CROW_DAMAGE_PCT, &mut ctx); // −30%
602
+ clock::set_for_testing(&mut clk, harvest_at);
603
+
604
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
605
+
606
+ // after_bonus = 6 * 200 / 100 = 12; final = 12 * 70 / 100 = 8
607
+ assert!(wheat::get(&us) == 8, 0);
608
+
609
+ clock::destroy_for_testing(clk);
610
+ std::unit_test::destroy(ds);
611
+ std::unit_test::destroy(us);
612
+ }
613
+
614
+ #[test]
615
+ fun test_harvest_accumulates_total_earned_over_two_plots() {
616
+ let mut ctx = sui::tx_context::dummy();
617
+ let ds = setup_dapp(&mut ctx);
618
+ let mut us = setup_player(100, &mut ctx);
619
+ give_seed(&mut us, CROP_WHEAT, 2, &mut ctx);
620
+
621
+ let mut clk = clock::create_for_testing(&mut ctx);
622
+ clock::set_for_testing(&mut clk, 1000);
623
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
624
+ farm_system::plant(&ds, &mut us, 1, CROP_WHEAT, &clk, &mut ctx);
625
+
626
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
627
+ clock::set_for_testing(&mut clk, harvest_at);
628
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
629
+ farm_system::harvest(&ds, &mut us, 1, &clk, &mut ctx);
630
+
631
+ // total_earned = 2 × (WHEAT_YIELD × WHEAT_SELL) = 2 × 48 = 96
632
+ assert!(profile::get_total_earned(&us) == 2 * WHEAT_YIELD * WHEAT_SELL, 0);
633
+
634
+ clock::destroy_for_testing(clk);
635
+ std::unit_test::destroy(ds);
636
+ std::unit_test::destroy(us);
637
+ }
638
+
639
+ #[test]
640
+ fun test_harvest_season_stats_accumulated_correctly() {
641
+ let mut ctx = sui::tx_context::dummy();
642
+ let ds = setup_dapp(&mut ctx);
643
+ let mut us = setup_player(100, &mut ctx);
644
+ give_seed(&mut us, CROP_CORN, 1, &mut ctx);
645
+
646
+ let clk = plant_then_advance(&ds, &mut us, 0, CROP_CORN, 0, &mut ctx);
647
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
648
+
649
+ assert!(season_stats::has(&us), 0);
650
+ assert!(season_stats::get(&us) == CORN_YIELD * CORN_SELL, 1); // 140
651
+
652
+ clock::destroy_for_testing(clk);
653
+ std::unit_test::destroy(ds);
654
+ std::unit_test::destroy(us);
655
+ }
656
+
657
+ #[test]
658
+ fun test_harvest_then_replant_same_plot_succeeds() {
659
+ let mut ctx = sui::tx_context::dummy();
660
+ let ds = setup_dapp(&mut ctx);
661
+ let mut us = setup_player(100, &mut ctx);
662
+ give_seed(&mut us, CROP_WHEAT, 2, &mut ctx); // 2 seeds: 1 for first plant, 1 for replant
663
+
664
+ let mut clk = clock::create_for_testing(&mut ctx);
665
+ clock::set_for_testing(&mut clk, 1000);
666
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
667
+
668
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
669
+ clock::set_for_testing(&mut clk, harvest_at);
670
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
671
+
672
+ // Re-plant on the same plot using a second seed
673
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
674
+ assert!(farm_plot::get_crop_type(&us, 0) == CROP_WHEAT, 0);
675
+ // Both seeds consumed; harvested crops (WHEAT_YIELD) still intact in crop resource
676
+ assert!(wheat_seed::get(&us) == 0, 1);
677
+ assert!(wheat::get(&us) == WHEAT_YIELD, 2);
678
+
679
+ clock::destroy_for_testing(clk);
680
+ std::unit_test::destroy(ds);
681
+ std::unit_test::destroy(us);
682
+ }
683
+
684
+ // ── failure cases ─────────────────────────────────────────────────────────────
685
+
686
+ #[test]
687
+ #[expected_failure]
688
+ fun test_harvest_fails_not_registered() {
689
+ let mut ctx = sui::tx_context::dummy();
690
+ let ds = setup_dapp(&mut ctx);
691
+ let mut us = init_test::create_user_storage_for_testing(ctx.sender(), &mut ctx);
692
+ let clk = clock::create_for_testing(&mut ctx);
693
+
694
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
695
+
696
+ clock::destroy_for_testing(clk);
697
+ std::unit_test::destroy(ds);
698
+ std::unit_test::destroy(us);
699
+ }
700
+
701
+ #[test]
702
+ #[expected_failure]
703
+ fun test_harvest_fails_plot_record_does_not_exist() {
704
+ let mut ctx = sui::tx_context::dummy();
705
+ let ds = setup_dapp(&mut ctx);
706
+ let mut us = setup_player(100, &mut ctx);
707
+ let clk = clock::create_for_testing(&mut ctx);
708
+
709
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx); // no plot record set
710
+
711
+ clock::destroy_for_testing(clk);
712
+ std::unit_test::destroy(ds);
713
+ std::unit_test::destroy(us);
714
+ }
715
+
716
+ #[test]
717
+ #[expected_failure]
718
+ fun test_harvest_fails_plot_is_empty_after_previous_harvest() {
719
+ let mut ctx = sui::tx_context::dummy();
720
+ let ds = setup_dapp(&mut ctx);
721
+ let mut us = setup_player(100, &mut ctx);
722
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
723
+
724
+ let mut clk = clock::create_for_testing(&mut ctx);
725
+ clock::set_for_testing(&mut clk, 1000);
726
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
727
+
728
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
729
+ clock::set_for_testing(&mut clk, harvest_at);
730
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx); // first: ok
731
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx); // second: plot is empty
732
+
733
+ clock::destroy_for_testing(clk);
734
+ std::unit_test::destroy(ds);
735
+ std::unit_test::destroy(us);
736
+ }
737
+
738
+ #[test]
739
+ #[expected_failure]
740
+ fun test_harvest_fails_one_ms_before_ready() {
741
+ let mut ctx = sui::tx_context::dummy();
742
+ let ds = setup_dapp(&mut ctx);
743
+ let mut us = setup_player(100, &mut ctx);
744
+ give_seed(&mut us, CROP_WHEAT, 1, &mut ctx);
745
+
746
+ let mut clk = clock::create_for_testing(&mut ctx);
747
+ clock::set_for_testing(&mut clk, 1000);
748
+ farm_system::plant(&ds, &mut us, 0, CROP_WHEAT, &clk, &mut ctx);
749
+
750
+ let harvest_at = farm_plot::get_harvest_at(&us, 0);
751
+ clock::set_for_testing(&mut clk, harvest_at - 1); // 1 ms too early
752
+
753
+ farm_system::harvest(&ds, &mut us, 0, &clk, &mut ctx);
754
+
755
+ clock::destroy_for_testing(clk);
756
+ std::unit_test::destroy(ds);
757
+ std::unit_test::destroy(us);
758
+ }
759
+
760
+ // ═════════════════════════════════════════════════════════════════════════════
761
+ // shop_system::buy_seeds
762
+ // ═════════════════════════════════════════════════════════════════════════════
763
+
764
+ #[test]
765
+ fun test_buy_seeds_wheat_deducts_gold_adds_inventory() {
766
+ let mut ctx = sui::tx_context::dummy();
767
+ let ds = setup_dapp(&mut ctx);
768
+ let mut us = setup_player(100, &mut ctx);
769
+
770
+ shop_system::buy_seeds(&ds, &mut us, CROP_WHEAT, 3, &mut ctx);
771
+
772
+ assert!(gold::get(&us) == 100 - 3 * WHEAT_PRICE, 0); // 85
773
+ assert!(wheat_seed::get(&us) == 3, 1);
774
+
775
+ std::unit_test::destroy(ds);
776
+ std::unit_test::destroy(us);
777
+ }
778
+
779
+ #[test]
780
+ fun test_buy_seeds_corn_correct_price() {
781
+ let mut ctx = sui::tx_context::dummy();
782
+ let ds = setup_dapp(&mut ctx);
783
+ let mut us = setup_player(100, &mut ctx);
784
+
785
+ shop_system::buy_seeds(&ds, &mut us, CROP_CORN, 2, &mut ctx);
786
+
787
+ assert!(gold::get(&us) == 100 - 2 * CORN_PRICE, 0); // 60
788
+ assert!(corn_seed::get(&us) == 2, 1);
789
+
790
+ std::unit_test::destroy(ds);
791
+ std::unit_test::destroy(us);
792
+ }
793
+
794
+ #[test]
795
+ fun test_buy_seeds_carrot_correct_price() {
796
+ let mut ctx = sui::tx_context::dummy();
797
+ let ds = setup_dapp(&mut ctx);
798
+ let mut us = setup_player(100, &mut ctx);
799
+
800
+ shop_system::buy_seeds(&ds, &mut us, CROP_CARROT, 1, &mut ctx);
801
+
802
+ assert!(gold::get(&us) == 100 - CARROT_PRICE, 0); // 40
803
+ assert!(carrot_seed::get(&us) == 1, 1);
804
+
805
+ std::unit_test::destroy(ds);
806
+ std::unit_test::destroy(us);
807
+ }
808
+
809
+ #[test]
810
+ fun test_buy_seeds_pumpkin_correct_price() {
811
+ let mut ctx = sui::tx_context::dummy();
812
+ let ds = setup_dapp(&mut ctx);
813
+ let mut us = setup_player(200, &mut ctx);
814
+
815
+ shop_system::buy_seeds(&ds, &mut us, CROP_PUMPKIN, 4, &mut ctx);
816
+
817
+ assert!(gold::get(&us) == 200 - 4 * PUMPKIN_PRICE, 0); // 40
818
+ assert!(pumpkin_seed::get(&us) == 4, 1);
819
+
820
+ std::unit_test::destroy(ds);
821
+ std::unit_test::destroy(us);
822
+ }
823
+
824
+ #[test]
825
+ fun test_buy_seeds_exact_gold_boundary() {
826
+ let mut ctx = sui::tx_context::dummy();
827
+ let ds = setup_dapp(&mut ctx);
828
+ let mut us = setup_player(WHEAT_PRICE, &mut ctx); // exactly 5
829
+
830
+ shop_system::buy_seeds(&ds, &mut us, CROP_WHEAT, 1, &mut ctx);
831
+
832
+ assert!(gold::get(&us) == 0, 0);
833
+ assert!(wheat_seed::get(&us) == 1, 1);
834
+
835
+ std::unit_test::destroy(ds);
836
+ std::unit_test::destroy(us);
837
+ }
838
+
839
+ #[test]
840
+ #[expected_failure]
841
+ fun test_buy_seeds_fails_not_registered() {
842
+ let mut ctx = sui::tx_context::dummy();
843
+ let ds = setup_dapp(&mut ctx);
844
+ let mut us = init_test::create_user_storage_for_testing(ctx.sender(), &mut ctx);
845
+
846
+ shop_system::buy_seeds(&ds, &mut us, CROP_WHEAT, 1, &mut ctx);
847
+
848
+ std::unit_test::destroy(ds);
849
+ std::unit_test::destroy(us);
850
+ }
851
+
852
+ #[test]
853
+ #[expected_failure]
854
+ fun test_buy_seeds_fails_crop_type_none() {
855
+ let mut ctx = sui::tx_context::dummy();
856
+ let ds = setup_dapp(&mut ctx);
857
+ let mut us = setup_player(100, &mut ctx);
858
+
859
+ shop_system::buy_seeds(&ds, &mut us, 0, 1, &mut ctx); // type 0 invalid
860
+
861
+ std::unit_test::destroy(ds);
862
+ std::unit_test::destroy(us);
863
+ }
864
+
865
+ #[test]
866
+ #[expected_failure]
867
+ fun test_buy_seeds_fails_crop_type_out_of_range() {
868
+ let mut ctx = sui::tx_context::dummy();
869
+ let ds = setup_dapp(&mut ctx);
870
+ let mut us = setup_player(100, &mut ctx);
871
+
872
+ shop_system::buy_seeds(&ds, &mut us, 5, 1, &mut ctx); // type 5 invalid
873
+
874
+ std::unit_test::destroy(ds);
875
+ std::unit_test::destroy(us);
876
+ }
877
+
878
+ #[test]
879
+ #[expected_failure]
880
+ fun test_buy_seeds_fails_count_zero() {
881
+ let mut ctx = sui::tx_context::dummy();
882
+ let ds = setup_dapp(&mut ctx);
883
+ let mut us = setup_player(100, &mut ctx);
884
+
885
+ shop_system::buy_seeds(&ds, &mut us, CROP_WHEAT, 0, &mut ctx);
886
+
887
+ std::unit_test::destroy(ds);
888
+ std::unit_test::destroy(us);
889
+ }
890
+
891
+ #[test]
892
+ #[expected_failure]
893
+ fun test_buy_seeds_fails_insufficient_gold_by_one() {
894
+ let mut ctx = sui::tx_context::dummy();
895
+ let ds = setup_dapp(&mut ctx);
896
+ let mut us = setup_player(WHEAT_PRICE - 1, &mut ctx); // 4 < 5
897
+
898
+ shop_system::buy_seeds(&ds, &mut us, CROP_WHEAT, 1, &mut ctx);
899
+
900
+ std::unit_test::destroy(ds);
901
+ std::unit_test::destroy(us);
902
+ }
903
+
904
+ // ═════════════════════════════════════════════════════════════════════════════
905
+ // shop_system::buy_extra_plot
906
+ // ═════════════════════════════════════════════════════════════════════════════
907
+
908
+ #[test]
909
+ fun test_buy_extra_plot_increments_plots_and_deducts_gold() {
910
+ let mut ctx = sui::tx_context::dummy();
911
+ let ds = setup_dapp(&mut ctx);
912
+ let mut us = setup_player(300, &mut ctx); // starting: 3 plots, 300 gold
913
+
914
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
915
+
916
+ assert!(gold::get(&us) == 300 - PLOT_PRICE, 0); // 100
917
+ assert!(profile::get_plots_owned(&us) == 4, 1);
918
+
919
+ std::unit_test::destroy(ds);
920
+ std::unit_test::destroy(us);
921
+ }
922
+
923
+ #[test]
924
+ fun test_buy_extra_plot_exact_gold_boundary() {
925
+ let mut ctx = sui::tx_context::dummy();
926
+ let ds = setup_dapp(&mut ctx);
927
+ let mut us = setup_player(PLOT_PRICE, &mut ctx); // exactly 200
928
+
929
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
930
+
931
+ assert!(gold::get(&us) == 0, 0);
932
+ assert!(profile::get_plots_owned(&us) == 4, 1);
933
+
934
+ std::unit_test::destroy(ds);
935
+ std::unit_test::destroy(us);
936
+ }
937
+
938
+ #[test]
939
+ fun test_buy_extra_plot_up_to_max_12() {
940
+ let mut ctx = sui::tx_context::dummy();
941
+ let ds = setup_dapp(&mut ctx);
942
+ // Buy 3 extra plots (3 → 6) to verify repeated purchases work
943
+ let mut us = setup_player(2000, &mut ctx);
944
+
945
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
946
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
947
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
948
+
949
+ assert!(profile::get_plots_owned(&us) == 6, 0);
950
+ assert!(gold::get(&us) == 2000 - 3 * PLOT_PRICE, 1); // 2000 - 600 = 1400
951
+
952
+ std::unit_test::destroy(ds);
953
+ std::unit_test::destroy(us);
954
+ }
955
+
956
+ #[test]
957
+ #[expected_failure]
958
+ fun test_buy_extra_plot_fails_not_registered() {
959
+ let mut ctx = sui::tx_context::dummy();
960
+ let ds = setup_dapp(&mut ctx);
961
+ let mut us = init_test::create_user_storage_for_testing(ctx.sender(), &mut ctx);
962
+
963
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
964
+
965
+ std::unit_test::destroy(ds);
966
+ std::unit_test::destroy(us);
967
+ }
968
+
969
+ #[test]
970
+ #[expected_failure]
971
+ fun test_buy_extra_plot_fails_at_max_12() {
972
+ let mut ctx = sui::tx_context::dummy();
973
+ let ds = setup_dapp(&mut ctx);
974
+ let mut us = init_test::create_user_storage_for_testing(ctx.sender(), &mut ctx);
975
+ gold::set(&mut us, 500, &mut ctx);
976
+ profile::set(&mut us, 0, 12, &mut ctx); // already at max
977
+
978
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
979
+
980
+ std::unit_test::destroy(ds);
981
+ std::unit_test::destroy(us);
982
+ }
983
+
984
+ #[test]
985
+ #[expected_failure]
986
+ fun test_buy_extra_plot_fails_insufficient_gold_by_one() {
987
+ let mut ctx = sui::tx_context::dummy();
988
+ let ds = setup_dapp(&mut ctx);
989
+ let mut us = setup_player(PLOT_PRICE - 1, &mut ctx); // 199
990
+
991
+ shop_system::buy_extra_plot(&ds, &mut us, &mut ctx);
992
+
993
+ std::unit_test::destroy(ds);
994
+ std::unit_test::destroy(us);
995
+ }
996
+
997
+ // ═════════════════════════════════════════════════════════════════════════════
998
+ // shop_system::sell_crops
999
+ // ═════════════════════════════════════════════════════════════════════════════
1000
+
1001
+ #[test]
1002
+ fun test_sell_wheat_burns_crops_adds_gold() {
1003
+ let mut ctx = sui::tx_context::dummy();
1004
+ let ds = setup_dapp(&mut ctx);
1005
+ let mut us = setup_player(0, &mut ctx);
1006
+ give_crop(&mut us, CROP_WHEAT, 6, &mut ctx);
1007
+
1008
+ shop_system::sell_crops(&ds, &mut us, CROP_WHEAT, 6, &mut ctx);
1009
+
1010
+ assert!(wheat::get(&us) == 0, 0);
1011
+ assert!(gold::get(&us) == 6 * WHEAT_SELL, 1); // 48
1012
+
1013
+ std::unit_test::destroy(ds);
1014
+ std::unit_test::destroy(us);
1015
+ }
1016
+
1017
+ #[test]
1018
+ fun test_sell_corn_correct_price() {
1019
+ let mut ctx = sui::tx_context::dummy();
1020
+ let ds = setup_dapp(&mut ctx);
1021
+ let mut us = setup_player(0, &mut ctx);
1022
+ give_crop(&mut us, CROP_CORN, 4, &mut ctx);
1023
+
1024
+ shop_system::sell_crops(&ds, &mut us, CROP_CORN, 4, &mut ctx);
1025
+
1026
+ assert!(corn::get(&us) == 0, 0);
1027
+ assert!(gold::get(&us) == 4 * CORN_SELL, 1); // 140
1028
+
1029
+ std::unit_test::destroy(ds);
1030
+ std::unit_test::destroy(us);
1031
+ }
1032
+
1033
+ #[test]
1034
+ fun test_sell_partial_amount_leaves_remainder() {
1035
+ let mut ctx = sui::tx_context::dummy();
1036
+ let ds = setup_dapp(&mut ctx);
1037
+ let mut us = setup_player(0, &mut ctx);
1038
+ give_crop(&mut us, CROP_WHEAT, 10, &mut ctx);
1039
+
1040
+ shop_system::sell_crops(&ds, &mut us, CROP_WHEAT, 4, &mut ctx);
1041
+
1042
+ assert!(wheat::get(&us) == 6, 0);
1043
+ assert!(gold::get(&us) == 4 * WHEAT_SELL, 1); // 32
1044
+
1045
+ std::unit_test::destroy(ds);
1046
+ std::unit_test::destroy(us);
1047
+ }
1048
+
1049
+ #[test]
1050
+ fun test_sell_pumpkin_and_carrot_correct_prices() {
1051
+ let mut ctx = sui::tx_context::dummy();
1052
+ let ds = setup_dapp(&mut ctx);
1053
+ let mut us = setup_player(0, &mut ctx);
1054
+ give_crop(&mut us, CROP_PUMPKIN, 2, &mut ctx);
1055
+ give_crop(&mut us, CROP_CARROT, 3, &mut ctx);
1056
+
1057
+ shop_system::sell_crops(&ds, &mut us, CROP_PUMPKIN, 2, &mut ctx);
1058
+ shop_system::sell_crops(&ds, &mut us, CROP_CARROT, 3, &mut ctx);
1059
+
1060
+ assert!(pumpkin::get(&us) == 0, 0);
1061
+ assert!(carrot::get(&us) == 0, 1);
1062
+ assert!(gold::get(&us) == 2 * PUMPKIN_SELL + 3 * CARROT_SELL, 2); // 200 + 360 = 560
1063
+
1064
+ std::unit_test::destroy(ds);
1065
+ std::unit_test::destroy(us);
1066
+ }
1067
+
1068
+ #[test]
1069
+ #[expected_failure]
1070
+ fun test_sell_crops_fails_not_registered() {
1071
+ let mut ctx = sui::tx_context::dummy();
1072
+ let ds = setup_dapp(&mut ctx);
1073
+ let mut us = init_test::create_user_storage_for_testing(ctx.sender(), &mut ctx);
1074
+
1075
+ shop_system::sell_crops(&ds, &mut us, CROP_WHEAT, 1, &mut ctx);
1076
+
1077
+ std::unit_test::destroy(ds);
1078
+ std::unit_test::destroy(us);
1079
+ }
1080
+
1081
+ #[test]
1082
+ #[expected_failure]
1083
+ fun test_sell_crops_fails_invalid_crop_type() {
1084
+ let mut ctx = sui::tx_context::dummy();
1085
+ let ds = setup_dapp(&mut ctx);
1086
+ let mut us = setup_player(0, &mut ctx);
1087
+
1088
+ shop_system::sell_crops(&ds, &mut us, 0, 1, &mut ctx);
1089
+
1090
+ std::unit_test::destroy(ds);
1091
+ std::unit_test::destroy(us);
1092
+ }
1093
+
1094
+ #[test]
1095
+ #[expected_failure]
1096
+ fun test_sell_crops_fails_amount_zero() {
1097
+ let mut ctx = sui::tx_context::dummy();
1098
+ let ds = setup_dapp(&mut ctx);
1099
+ let mut us = setup_player(0, &mut ctx);
1100
+ give_crop(&mut us, CROP_WHEAT, 5, &mut ctx);
1101
+
1102
+ shop_system::sell_crops(&ds, &mut us, CROP_WHEAT, 0, &mut ctx);
1103
+
1104
+ std::unit_test::destroy(ds);
1105
+ std::unit_test::destroy(us);
1106
+ }
1107
+
1108
+ #[test]
1109
+ #[expected_failure]
1110
+ fun test_sell_crops_fails_more_than_owned() {
1111
+ let mut ctx = sui::tx_context::dummy();
1112
+ let ds = setup_dapp(&mut ctx);
1113
+ let mut us = setup_player(0, &mut ctx);
1114
+ give_crop(&mut us, CROP_WHEAT, 3, &mut ctx);
1115
+
1116
+ shop_system::sell_crops(&ds, &mut us, CROP_WHEAT, 4, &mut ctx); // 4 > 3 owned
1117
+
1118
+ std::unit_test::destroy(ds);
1119
+ std::unit_test::destroy(us);
1120
+ }
1121
+
1122
+ // ═════════════════════════════════════════════════════════════════════════════
1123
+ // crow_system::place_scarecrow
1124
+ // ═════════════════════════════════════════════════════════════════════════════
1125
+
1126
+ #[test]
1127
+ fun test_place_scarecrow_deducts_gold_and_sets_expiry() {
1128
+ let mut ctx = sui::tx_context::dummy();
1129
+ let ds = setup_dapp(&mut ctx);
1130
+ let mut us = setup_player(50, &mut ctx);
1131
+ let mut clk = clock::create_for_testing(&mut ctx);
1132
+ clock::set_for_testing(&mut clk, 1000);
1133
+
1134
+ crow_system::place_scarecrow(&ds, &mut us, &clk, &mut ctx);
1135
+
1136
+ assert!(gold::get(&us) == 40, 0); // 50 − 10 = 40
1137
+ assert!(scarecrow::has(&us), 1);
1138
+ // SCARECROW_DURATION = 4 h = 14_400_000 ms
1139
+ assert!(scarecrow::get(&us) == 1000 + 14_400_000, 2);
1140
+
1141
+ clock::destroy_for_testing(clk);
1142
+ std::unit_test::destroy(ds);
1143
+ std::unit_test::destroy(us);
1144
+ }
1145
+
1146
+ #[test]
1147
+ fun test_place_scarecrow_exact_gold_boundary() {
1148
+ let mut ctx = sui::tx_context::dummy();
1149
+ let ds = setup_dapp(&mut ctx);
1150
+ let mut us = setup_player(10, &mut ctx); // exactly 10
1151
+ let clk = clock::create_for_testing(&mut ctx);
1152
+
1153
+ crow_system::place_scarecrow(&ds, &mut us, &clk, &mut ctx);
1154
+
1155
+ assert!(gold::get(&us) == 0, 0);
1156
+ assert!(scarecrow::has(&us), 1);
1157
+
1158
+ clock::destroy_for_testing(clk);
1159
+ std::unit_test::destroy(ds);
1160
+ std::unit_test::destroy(us);
1161
+ }
1162
+
1163
+ #[test]
1164
+ #[expected_failure]
1165
+ fun test_place_scarecrow_fails_not_registered() {
1166
+ let mut ctx = sui::tx_context::dummy();
1167
+ let ds = setup_dapp(&mut ctx);
1168
+ let mut us = init_test::create_user_storage_for_testing(ctx.sender(), &mut ctx);
1169
+ let clk = clock::create_for_testing(&mut ctx);
1170
+
1171
+ crow_system::place_scarecrow(&ds, &mut us, &clk, &mut ctx);
1172
+
1173
+ clock::destroy_for_testing(clk);
1174
+ std::unit_test::destroy(ds);
1175
+ std::unit_test::destroy(us);
1176
+ }
1177
+
1178
+ #[test]
1179
+ #[expected_failure]
1180
+ fun test_place_scarecrow_fails_insufficient_gold_by_one() {
1181
+ let mut ctx = sui::tx_context::dummy();
1182
+ let ds = setup_dapp(&mut ctx);
1183
+ let mut us = setup_player(9, &mut ctx); // 1 short of 10
1184
+ let clk = clock::create_for_testing(&mut ctx);
1185
+
1186
+ crow_system::place_scarecrow(&ds, &mut us, &clk, &mut ctx);
1187
+
1188
+ clock::destroy_for_testing(clk);
1189
+ std::unit_test::destroy(ds);
1190
+ std::unit_test::destroy(us);
1191
+ }
1192
+ }