From 4f49b16079b27d7ce633619e4cddfdf2bffbc952 Mon Sep 17 00:00:00 2001 From: cashmere Date: Fri, 4 Sep 2026 09:05:24 +0200 Subject: initial commit --- test/Greek-Lipsum-1.txt | 77 + test/Greek-Lipsum-2.txt | 77 + test/amend.test | 403 + test/clean.test | 193 + test/cmdline.test | 54 + test/commit-warning.test | 166 + test/contains-selector.test | 55 + test/csp1.html | 18 + test/delta1.test | 60 + test/diff-test-1.wiki | 60 + test/diff.test | 162 + test/fake-editor.tcl | 98 + test/file1.test | 104 + test/fileStat.th1 | 102 + test/fileage-test-1.wiki | 14 + test/glob.test | 190 + test/graph-test-1.wiki | 119 + test/graph-test-2.md | 72 + test/json.test | 925 + test/link-tester.html | 82 + test/link-tester.js | 224 + test/link-tester.json | 68 + test/many-www.tcl | 81 + test/markdown-test1.md | 25 + test/markdown-test2.md | 79 + test/markdown-test3.md | 256 + test/merge1.test | 433 + test/merge2.test | 49 + test/merge3.test | 653 + test/merge4.test | 105 + test/merge5.test | 319 + test/merge5_repo.sql | 391 + test/merge6.test | 71 + test/merge_exe.test | 93 + test/merge_renames.test | 559 + test/merge_renames_2.test | 59 + test/merge_warn.test | 60 + test/mv-rm.test | 470 + test/org.test | 64 + test/release-checklist.wiki | 121 + test/reserved-names.test | 121 + test/revert.test | 358 + test/rewrite-test-output.tcl | 645 + test/set-manifest.test | 159 + test/settings-repo.test | 266 + test/settings.test.off | 138 + test/stash.test | 394 + test/subdir with spaces/filename with spaces.txt | 2 + test/subdir-b/readme.txt | 3 + test/subdir/README.html | 15 + test/subdir/one/readme.wiki | 9 + test/subdir/one/two/three/four/five/six/readme.txt | 2 + test/symlinks.test | 111 + test/test-page++.wiki | 7 + test/tester.tcl | 1184 + test/th1-docs-input.txt | 4 + test/th1-docs.test | 76 + test/th1-hooks-input.txt | 4 + test/th1-hooks.test | 237 + test/th1-repo.test | 88 + test/th1-taint.test | 84 + test/th1-tcl.test | 189 + test/th1-tcl1.txt | 29 + test/th1-tcl2.txt | 19 + test/th1-tcl3.txt | 9 + test/th1-tcl4.txt | 9 + test/th1-tcl5.txt | 9 + test/th1-tcl6.txt | 9 + test/th1-tcl7.txt | 19 + test/th1-tcl8.txt | 14 + test/th1-tcl9.txt | 9 + test/th1.test | 1706 ++ test/unversioned.test | 478 + test/update-test-1.sh | 44 + test/update-test-2.sh | 44 + test/update.test | 247 + test/utf.test | 26596 +++++++++++++++++++ test/utf16be.txt | Bin 0 -> 1566 bytes test/utf16le.txt | Bin 0 -> 1566 bytes test/utf8-comment.txt | 1 + test/valgrind-www.tcl | 57 + test/wiki.test | 414 + 82 files changed, 41020 insertions(+) create mode 100644 test/Greek-Lipsum-1.txt create mode 100644 test/Greek-Lipsum-2.txt create mode 100644 test/amend.test create mode 100644 test/clean.test create mode 100644 test/cmdline.test create mode 100644 test/commit-warning.test create mode 100644 test/contains-selector.test create mode 100644 test/csp1.html create mode 100644 test/delta1.test create mode 100644 test/diff-test-1.wiki create mode 100644 test/diff.test create mode 100644 test/fake-editor.tcl create mode 100644 test/file1.test create mode 100644 test/fileStat.th1 create mode 100644 test/fileage-test-1.wiki create mode 100644 test/glob.test create mode 100644 test/graph-test-1.wiki create mode 100644 test/graph-test-2.md create mode 100644 test/json.test create mode 100644 test/link-tester.html create mode 100644 test/link-tester.js create mode 100644 test/link-tester.json create mode 100644 test/many-www.tcl create mode 100644 test/markdown-test1.md create mode 100644 test/markdown-test2.md create mode 100644 test/markdown-test3.md create mode 100644 test/merge1.test create mode 100644 test/merge2.test create mode 100644 test/merge3.test create mode 100644 test/merge4.test create mode 100644 test/merge5.test create mode 100644 test/merge5_repo.sql create mode 100644 test/merge6.test create mode 100644 test/merge_exe.test create mode 100644 test/merge_renames.test create mode 100644 test/merge_renames_2.test create mode 100644 test/merge_warn.test create mode 100644 test/mv-rm.test create mode 100644 test/org.test create mode 100644 test/release-checklist.wiki create mode 100644 test/reserved-names.test create mode 100644 test/revert.test create mode 100644 test/rewrite-test-output.tcl create mode 100644 test/set-manifest.test create mode 100644 test/settings-repo.test create mode 100644 test/settings.test.off create mode 100644 test/stash.test create mode 100644 test/subdir with spaces/filename with spaces.txt create mode 100644 test/subdir-b/readme.txt create mode 100644 test/subdir/README.html create mode 100644 test/subdir/one/readme.wiki create mode 100644 test/subdir/one/two/three/four/five/six/readme.txt create mode 100644 test/symlinks.test create mode 100644 test/test-page++.wiki create mode 100644 test/tester.tcl create mode 100644 test/th1-docs-input.txt create mode 100644 test/th1-docs.test create mode 100644 test/th1-hooks-input.txt create mode 100644 test/th1-hooks.test create mode 100644 test/th1-repo.test create mode 100644 test/th1-taint.test create mode 100644 test/th1-tcl.test create mode 100644 test/th1-tcl1.txt create mode 100644 test/th1-tcl2.txt create mode 100644 test/th1-tcl3.txt create mode 100644 test/th1-tcl4.txt create mode 100644 test/th1-tcl5.txt create mode 100644 test/th1-tcl6.txt create mode 100644 test/th1-tcl7.txt create mode 100644 test/th1-tcl8.txt create mode 100644 test/th1-tcl9.txt create mode 100644 test/th1.test create mode 100644 test/unversioned.test create mode 100644 test/update-test-1.sh create mode 100644 test/update-test-2.sh create mode 100644 test/update.test create mode 100644 test/utf.test create mode 100644 test/utf16be.txt create mode 100644 test/utf16le.txt create mode 100644 test/utf8-comment.txt create mode 100644 test/valgrind-www.tcl create mode 100644 test/wiki.test (limited to 'test') diff --git a/test/Greek-Lipsum-1.txt b/test/Greek-Lipsum-1.txt new file mode 100644 index 0000000..644ad3d --- /dev/null +++ b/test/Greek-Lipsum-1.txt @@ -0,0 +1,77 @@ +Κυο εξ υνυμ δισπυθανδο, ερος αλιενυμ κυι θε. Νες εξ ελωκυενθιαμ +ινστρυσθιορ. Θεμπορ νοσθερ συ εως. Πυρθο μωφεθ μωδερατιυς ατ μελ. Συ δυο +αμετ ειυς. Πρι δεσωρε ινθεγρε ασυμσαν αδ, πρω αν ρεβυμ εφφισιανθυρ +νεσεσιταθιβυς. + +Νοσθρυμ συσιπιαντυρ ηας ει, ορναθυς ρεσυσαβο πρι ιδ, περ νολυισε οπωρθερε +ιδ. Θε παρτιενδω περτινασια ινσωρρυπτε φις. Δισθας φαβυλας γυβεργρεν εως +ιν, αλιι σολυμ ηις θε, ποσθυλανθ ασυσαμυς ετ ηας. Νο ινανι φαβυλας +θχεωπηραστυς ναμ, ευμ διστα ηομερω εα. Μαγνα φυγιθ υθ περ, εσθ ατ νοσθρυμ +δεσερυισε. + +Φις αυδιαμ λαβορες παθριοκυε εξ, ετ φευγιαθ δεφινιεβας σιθ. Αμετ εριπυιτ +δελισατα υσυ ετ, σενσιβυς φολυπθατιβυς περ εξ. Κυωδ ιγνωθα τιβικυε ατ εαμ, +νυλλα ηωνεσθαθις υθ νες. Φιξ αν μυτατ εξερσι λαβωρε. Σεδ νονυμυ κυοδσι +δελενιτ νε, συμο φιδε εα κυι. Ποπυλω μαιορυμ περσεκυερις αν πρω. + +Σολυμ σωνφενιρε αδ ηας, αν ευμ σολυτα ρεγιονε προδεσεθ. Φερο λαβορες +σαλυταθυς θε δυο, ηις νε φερο βλανδιτ πραεσενθ, ιδ φις σολεατ φιφενδυμ. Συ +συμ μωδω συμμο δολορες. Θε ναμ πωσιθ φευγιαθ τινσιδυνθ. + +Υθ ιψυμ νεμωρε σαπιενθεμ μεα, ει εφερτι εφφισιενδι ηας. Ευμ αλβυσιυς +πραεσενθ συ, δεσωρε σεθερο ινδοστυμ μει ει. Ηις υθ συμμο μαλορυμ μανδαμυς, +κυι ιν συαφιθαθε περισυλις, ιισκυε οφφισιις κυο νο. Νε νονυμυ ηαβεμυς +πχιλωσοπηια φις. Ετ ηας υταμυρ ρεφορμιδανς. Ινερμις δεθραξιθ νεγλεγενθυρ +δυο υθ, τωρκυαθος δισεντιυνθ φιθυπερατοριβυς φιξ νε. Εα σεδ συας μελιυς, +φιμ προβο ινδοστυμ ρεπριμικυε ευ. + +Πρι ιν λυδυς αυδιρε, συμμο περτινασια σωνσεθεθυρ φις ιν, σιθ εξ επισυρι +μαλυισετ σωνσεπθαμ. Αν δετρασθο ελειφενδ εξπλισαρι πρω. Ιυδισο σομμοδο συμ +αδ. Δισαμ δισυντ φυλπυτατε ιν πρω, εξ ηις δελενιτ μαιεσθατις. Ρεβυμ νονυμυ +αππαρεατ σιθ εα, σιθ ιδ νυλλα σολεατ πεθενθιυμ, ει οπθιων περσεκυερις ευμ. +Υθ νισλ ινσωλενς φιξ, εσθ φερι ιισκυε αργυμενθυμ συ, σεθερο μολεστιε +αδιπισινγ ευ μεα. + +Ετ μεα μυσιυς λατινε, μει σεμπερ δεσερυντ περτινασια αν. Συ φενιαμ ποπυλω +αθωμωρυμ κυο. Νο ιυς ρεβυμ φιθυπεραθα δισπυτατιονι, ατ αλθερυμ χενδρεριτ +φιθυπεραθα συμ. Ευμ αυτεμ αππετερε αδιπισινγ ετ, νο κυο συας ελειφενδ. Εαμ +θαλε δισαμ εξ. + +Ετ σομμοδο λεγενδως φελ, διαμ φωλυπθαρια νο μελ, δυο φελιτ νεμωρε αδ. Αν +εξπετενδα συαφιθαθε φελ, ενιμ ασυμσαν περ αδ, εα φιμ μωδω υνυμ. Εα κυωδ +προβο περσεσυτι φελ, ευ φερι πρωπριαε ινσιδεριντ νες. Εξ νες οδιο δελενιτ, +ελιτ ιυδισο ινθεγρε δυο ιδ. Μελ αλικυιπ περισυλις ετ, ατ ηας αυγυε λαβορες +ασεντιορ. + +Συ νυλλα δωσενδι δεφινιτιωνες φελ. Δωλορε δισερετ ρεφορμιδανς αδ πρω. +Εφερτι πρωβατυς υρβανιθας νο μελ. Ιν φιξ φασεθε δεθραξιθ ομιθταντυρ, ζριλ +υτιναμ παθριοκυε συ νες. Κυο ει δισενθιετ ασομμοδαρε. + +Ηας θε ομνεσκυε δελισαθισιμι. Εξερσι δελισατα ινιμισυς ευμ ευ, ιδ ελιτρ +μελιορε αβχορρεανθ εσθ, εως οπθιων προδεσεθ σονσεσθεθυερ ιν. Ναμ διαμ ασυμ +τεμποριβυς αν. Σομμυνε δεφινιθιονεμ κυο ιν, ηας νωμιναφι φιφενδυμ ατ. +Ομνεσκυε δεφινιεβας μεα θε. + +Εαμ σανστυς αλβυσιυς ευ, φελ στετ επισυρι ιν, κυο αδ περτιναξ σενσεριτ +τωρκυαθος. Λαβωρε νυσκυαμ ιν κυι, ερος σαεπε τιβικυε εσθ ατ. Φερο υτιναμ +φελ νε, αδ απεριρι ομιθταντυρ δεφινιτιωνες δυο. Ινφενιρε ελειφενδ παθριοκυε +εξ ναμ. Ιδ ναμ μινιμ υθροκυε. Αδ ναθυμ αππετερε σεα. + +Μολλις φολυμυς κυι νο, θε φιμ υβικυε αδιπισι διγνισιμ. Νοβις νοσθρω +μενανδρι υσυ νο, πριμα ελιτρ κυαεκυε ιδ ηας. Πρω εα παρτεμ δομινγ. Θε +φασεθε αυδιρε φολυπθατιβυς ιυς. Φις δεθραξιθ ινφενιρε ετ, αν ιυς πωσθεα +μεδιοσριθαθεμ. + +Εα αδχυς υταμυρ φις. Σιβω λαυδεμ υσυ αδ, φις λεγιμυς πλασεραθ φερθερεμ συ. +Φιμ ατ ειυς αλθερυμ φιθυπερατοριβυς, ατ λατινε ηαβεμυς φολυτπατ μεα. Γραεσω +λυσιλιυς εα φελ. + +Θε φιξ βρυτε συμμο, φελ ωμιτθαμ ιμπερδιετ εξ. Μεα ιν μωδω νυμκυαμ, σεα +τρασθατος εξπετενδα αδ. Γραεσε πλαθονεμ ρεπυδιανδαε φιξ εα, εα ετιαμ +σωνσθιτυθο ασυεφεριθ σιθ. Ατ πυρθο ναθυμ σονγυε φιξ, κυι ετ δισαμ ινερμις +ινιμισυς. + +Περ υθ διστα ινθεγρε, περ ρεκυε φιερενθ αδ. Νε δεσερυντ ινφενιρε σωνσεθεθυρ +μει, αν ηομερω αργυμενθυμ ρεπυδιανδαε περ, ηις σωνσυλ μελιορε ινθελλεγαμ +υθ. Νες εα λαβιθυρ δολορεμ υλλαμσορπερ. Μει εσεντ νεσεσιταθιβυς ιν, αφφερθ +σαυσαε ινθερεσετ ηας αν. diff --git a/test/Greek-Lipsum-2.txt b/test/Greek-Lipsum-2.txt new file mode 100644 index 0000000..eef9bec --- /dev/null +++ b/test/Greek-Lipsum-2.txt @@ -0,0 +1,77 @@ +Κυο εξ υνυμ δισπυθανδο, ερος αλιενυμ κυι θε. Νες εξ ελωκυενθιαμ +ινστρυσθιορ. Θεμπορ νοσθερ συ εως. Πυρθο μωφεθ μωδερατιυς ατ μελ. Συ δυο +αμετ ειυς. Πρι δεσωρε ινθεγρε ασυμσαν αδ, Φιξ αν ρεβυμ εφφισιανθυρ +νεσεσιταθιβυς. + +Νοσθρυμ συσιπιαντυρ ηας ει, ορναθυς ρεσυσαβο πρι ιδ, περ νολυισε +οπωρθερε ιδ. Θε παρτιενδω περτινασια ινσωρρυπτε φις. Δισθας φαβυλας +γυβεργρεν εως ιν, αλιι σολυμ ηις θε, ποσθυλανθ ασυσαμυς ετ ηας. Νο ινανι +φαβυλας θχεωπηραστυς ναμ, ευμ διστα ηομερω εα. Μαγνα φυγιθ υθ περ, εσθ +ατ νοσθρυμ δεσερυισε. + +Φις αυδιαμ λαβορες παθριοκυε εξ, ετ φευγιαθ δεφινιεβας σιθ. Αμετ εριπυιτ +δελισατα υσυ ετ, σενσιβυς φολυπθατιβυς περ εξ. Κυωδ ιγνωθα τιβικυε ατ +εαμ, νυλλα ηωνεσθαθις υθ νες. Φιξ αν μυτατ εξερσι λαβωρε. Σεδ νονυμυ +κυοδσι δελενιτ νε, συμο φιδε εα κυι. Ποπυλω μαιορυμ περσεκυερις αν πρω. + +Σολυμ σωνφενιρε αδ ηας, αν ευμ σολυτα ρεγιονε προδεσεθ. Φερο λαβορες +σαλυταθυς θε δυο, ηις νε φερο βλανδιτ πραεσενθ, ιδ φις σολεατ φιφενδυμ. +Συ συμ μωδω συμμο δολορες. Θε ναμ πωσιθ φευγιαθ τινσιδυνθ. + +Υθ ιψυμ νεμωρε σαπιενθεμ μεα, ει εφερτι εφφισιενδι ηας. Ευμ αλβυσιυς +πραεσενθ συ, δεσωρε σεθερο ινδοστυμ μει ει. Ηις υθ συμμο μαλορυμ +μανδαμυς, κυι ιν συαφιθαθε περισυλις, ιισκυε οφφισιις κυο νο. Νε νονυμυ +ηαβεμυς πχιλωσοπηια φις. Ετ ηας υταμυρ ρεφορμιδανς. Ινερμις δεθραξιθ +νεγλεγενθυρ δυο υθ, τωρκυαθος δισεντιυνθ φιθυπερατοριβυς φιξ νε. Εα σεδ +συας μελιυς, φιμ προβο ινδοστυμ ρεπριμικυε ευ. + +Πρι ιν λυδυς αυδιρε, συμμο περτινασια σωνσεθεθυρ φις ιν, σιθ εξ επισυρι +μαλυισετ σωνσεπθαμ. Αν δετρασθο ελειφενδ εξπλισαρι πρω. Ιυδισο σομμοδο +συμ αδ. Δισαμ δισυντ φυλπυτατε ιν πρω, εξ ηις δελενιτ μαιεσθατις. Ρεβυμ +νονυμυ αππαρεατ σιθ εα, σιθ ιδ νυλλα σολεατ πεθενθιυμ, ει οπθιων +περσεκυερις ευμ. Υθ νισλ ινσωλενς φιξ, εσθ φερι ιισκυε αργυμενθυμ συ, +σεθερο μολεστιε αδιπισινγ ευ μεα. + +Ετ μεα μυσιυς λατινε, μει σεμπερ δεσερυντ περτινασια αν. Συ φενιαμ +ποπυλω αθωμωρυμ κυο. Νο ιυς ρεβυμ φιθυπεραθα δισπυτατιονι, ατ αλθερυμ +χενδρεριτ φιθυπεραθα συμ. Ευμ αυτεμ αππετερε αδιπισινγ ετ, νο κυο συας +ελειφενδ. Εαμ θαλε δισαμ εξ. + +Ετ σομμοδο λεγενδως φελ, διαμ φωλυπθαρια νο μελ, δυο φελιτ νεμωρε αδ. Αν +εξπετενδα συαφιθαθε φελ, ενιμ ασυμσαν περ αδ, εα φιμ μωδω υνυμ. Εα κυωδ +προβο περσεσυτι φελ, ευ φερι πρωπριαε ινσιδεριντ νες. Εξ νες οδιο +δελενιτ, ελιτ ιυδισο ινθεγρε δυο ιδ. Μελ αλικυιπ περισυλις ετ, ατ ηας +αυγυε λαβορες ασεντιορ. + +Συ νυλλα δωσενδι δεφινιτιωνες φελ. Δωλορε δισερετ ρεφορμιδανς αδ πρω. +Εφερτι πρωβατυς υρβανιθας νο μελ. Ιν φιξ φασεθε δεθραξιθ ομιθταντυρ, +ζριλ υτιναμ παθριοκυε συ νες. Κυο ει δισενθιετ ασομμοδαρε. + +Ηας θε ομνεσκυε δελισαθισιμι. Εξερσι δελισατα ινιμισυς ευμ ευ, ιδ ελιτρ +μελιορε αβχορρεανθ εσθ, εως οπθιων προδεσεθ σονσεσθεθυερ ιν. Ναμ διαμ +ασυμ τεμποριβυς αν. Σομμυνε δεφινιθιονεμ κυο ιν, ηας νωμιναφι φιφενδυμ +ατ. Ομνεσκυε δεφινιεβας μεα θε. + +Εαμ σανστυς αλβυσιυς ευ, φελ στετ επισυρι ιν, κυο αδ περτιναξ σενσεριτ +τωρκυαθος. Λαβωρε νυσκυαμ ιν κυι, ερος σαεπε τιβικυε εσθ ατ. Φερο υτιναμ +φελ νε, αδ απεριρι ομιθταντυρ δεφινιτιωνες δυο. Ινφενιρε ελειφενδ +παθριοκυε εξ ναμ. Ιδ ναμ μινιμ υθροκυε. Αδ ναθυμ αππετερε σεα. + +Μολλις φολυμυς κυι νο, θε φιμ υβικυε αδιπισι διγνισιμ. Νοβις νοσθρω +μενανδρι υσυ νο, πριμα ελιτρ κυαεκυε ιδ ηας. Πρω εα παρτεμ δομινγ. Θε +φασεθε αυδιρε φολυπθατιβυς ιυς. Φις δεθραξιθ ινφενιρε ετ, αν ιυς πωσθεα +μεδιοσριθαθεμ. + +Εα αδχυς υταμυρ φις. Σιβω λαυδεμ υσυ αδ, φις λεγιμυς πλασεραθ φερθερεμ +συ. Φιμ ατ ειυς αλθερυμ φιθυπερατοριβυς, ατ λατινε ηαβεμυς φολυτπατ +μεα. Γραεσω λυσιλιυς εα φελ. + +Θε φιξ βρυτε συμμο, φελ ωμιτθαμ ιμπερδιετ εξ. Μεα ιν μωδω νυμκυαμ, σεα +τρασθατος εξπετενδα αδ. Γραεσε πλαθονεμ ρεπυδιανδαε φιξ εα, εα ετιαμ +σωνσθιτυθο ασυεφεριθ σιθ. Ατ πυρθο ναθυμ σονγυε φιξ, κυι ετ δισαμ +ινερμις ινιμισυς. + +Περ υθ διστα ινθεγρε, περ ρεκυε φιερενθ αδ. Νε δεσερυντ ινφενιρε +σωνσεθεθυρ μει, αν ηομερω αργυμενθυμ ρεπυδιανδαε περ, ηις σωνσυλ μελιορε +ινθελλεγαμ υθ. Νες εα λαβιθυρ δολορεμ υλλαμσορπερ. Μει εσεντ +νεσεσιταθιβυς ιν, αφφερθ σαυσαε ινθερεσετ ηας αν. diff --git a/test/amend.test b/test/amend.test new file mode 100644 index 0000000..61b2dbb --- /dev/null +++ b/test/amend.test @@ -0,0 +1,403 @@ +# +# Copyright (c) 2015 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests for the "amend" command. +# + +proc artifact_from_timeline {res var} { + upvar $var artid + regexp {(?x)[0-9]{2}(?::[0-9]{2}){2}\s+\[([0-9a-f]+)]} $res m artid +} + +proc manifest_comment {comment} { + string map [list { } {\\s} \n {\\n} \r {\\r}] $comment +} + +proc uuid_from_commit {res var} { + upvar $var HASH + regexp {^New_Version: ([0-9a-f]{40})[0-9a-f]*$} $res m HASH +} + +proc uuid_from_branch {res var} { + upvar $var HASH + regexp {^New branch: ([0-9a-f]{40})[0-9a-f]*$} $res m HASH +} + +proc uuid_from_checkout {var} { + global RESULT + upvar $var HASH + fossil status + regexp {checkout:\s+([0-9a-f]{40})[0-9a-f]*} $RESULT m HASH +} + +# Make sure we are not in an open repository and initialize new repository +test_setup + +######################################## +# Setup: Add file and commit # +######################################## + +if {![uuid_from_checkout HASHINIT]} { + test amend-checkout-failure false + test_cleanup_then_return +} +write_file datafile "data" +fossil add datafile +fossil commit -m "c1" +if {![uuid_from_commit $RESULT HASH]} { + test amend-setup-failure false + test_cleanup_then_return +} + +######################################## +# Test: -branch # +######################################## +set HASHB HASHB +write_file datafile "data.file" +fossil commit -m "c2" +if {![uuid_from_commit $RESULT HASHB]} { + test amend-branch.setup false +} +fossil amend $HASHB -branch amended-branch +test amend-branch-1.1 {[regexp {tags:\s+amended-branch} $RESULT]} +fossil branch ls +test amend-branch-1.2 {[string first "* amended-branch" $RESULT] != -1} +fossil tag list +test amend-branch-1.3 {[string first amended-branch $RESULT] != -1} +fossil tag list --raw $HASHB +test amend-branch-1.4 {[string first "branch=amended-branch" $RESULT] != -1} +test amend-branch-1.5 {[string first "sym-amended-branch" $RESULT] != -1} +fossil timeline -n 1 +test amend-branch-1.6 {[string match {*Move*to*branch*amended-branch*} $RESULT]} + +######################################## +# Test: -bgcolor # +######################################## +set tc 0 +foreach {color result} { + 0 0 + a a + abcdef #abcdef + abc123 #abc123 + 123efg 123efg + abcdefg abcdefg + abcdeg abcdeg + blue blue + acf #acf + 123 #123 + #1234 #1234 + 1234 1234 + 123456 #123456 +} { + incr tc + fossil amend $HASH -bgcolor $color + test amend-bgcolor-1.$tc.a {[string match "*hash:*$HASH*" $RESULT]} + fossil tag list --raw $HASH + test amend-bgcolor-1.$tc.b {[string first "bgcolor=$result" $RESULT] != -1} + fossil timeline -n 1 + test amend-bgcolor-1.$tc.c { + [string match "*Change*background*color*to*\"$result\"*" $RESULT] + } + if {[artifact_from_timeline $RESULT artid]} { + fossil artifact $artid + test amend-bgcolor-1.$tc.d { + [string match "*T +bgcolor $HASH* $result*" $RESULT] + } + } else { + if {$VERBOSE} { protOut "No artifact found in timeline output" } + test amend-bgcolor-1.$tc.d false + } +} +fossil amend $HASH -bgcolor {} +test amend-bgcolor-2.1 {[string match "*hash:*$HASH*" $RESULT]} +fossil tag list --raw $HASH +test amend-bgcolor-2.2 { + [string first "bgcolor=" $RESULT] == -1 && + [string first "bgcolor" $RESULT] != -1 +} +fossil timeline -n 1 +test amend-bgcolor-2.3 {[string match "*Cancel*background*color.*" $RESULT]} +if {[artifact_from_timeline $RESULT artid]} { + fossil artifact $artid + test amend-bgcolor-2.4 {[string match "*T -bgcolor $HASH*" $RESULT]} +} else { + if {$VERBOSE} { protOut "No artifact found in timeline output" } + test amend-bgcolor-2.4 false +} + +######################################## +# Test: -branchcolor # +######################################## +set HASH2 HASH2 +fossil branch new brclr $HASH +if {![uuid_from_branch $RESULT HASH2]} { + test amend-branchcolor.setup false +} +fossil update $HASH2 +fossil amend $HASH2 -branchcolor yellow +test amend-branchcolor-1.1 {[string match "*hash:*$HASH2*" $RESULT]} +fossil tag ls --raw $HASH2 +test amend-branchcolor-1.2 {[string first "bgcolor=yellow" $RESULT] != -1} +fossil timeline -n 1 +test amend-branchcolor-1.3 { + [string match {*Change*branch*background*color*to*"yellow".*} $RESULT] +} +if {[regexp {(?x)[0-9]{2}(?::[0-9]{2}){2}\s+\[([0-9a-f]+)]} $RESULT m artid]} { + fossil artifact $artid + test amend-branchcolor-1.4 { + [string match "*T \*bgcolor $HASH2* yellow*" $RESULT] + } +} else { + if {$VERBOSE} { protOut "No artifact found in timeline output" } + test amend-branchcolor-1.4 false +} + +set HASHN HASHN +write_file datafile "brclr" +fossil commit -m "brclr" +if {![uuid_from_commit $RESULT HASHN]} { + test amend-branchcolor-propagating.setup false +} +write_file datafile "bc1" +fossil commit -m "mc1" +write_file datafile "bc2" +fossil commit -m "mc2" +fossil amend $HASHN -branchcolor deadbe +test amend-branchcolor-2.1 {[string match "*hash:*$HASHN*" $RESULT]} +fossil tag ls --raw current +test amend-branchcolor-2.2 {[string first "bgcolor=#deadbe" $RESULT] != -1} +fossil timeline -n 1 +test amend-branchcolor-2.3 { + [string match {*Change*branch*background*color*to*"#deadbe".*} $RESULT] +} + +######################################## +# Test: -author # +######################################## +fossil amend $HASH -author author-test +test amend-author-1.1 {[string match {*comment:*(user:*author-test)*} $RESULT]} +fossil tag ls --raw $HASH +test amend-author-1.2 {[string first "user=author-test" $RESULT] != -1} +fossil timeline -n 1 +test amend-author-1.3 {[string match {*Change*user*to*"author-test".*} $RESULT]} + +######################################## +# Test: -date # +######################################## +set timestamp [clock scan yesterday] +set date [clock format $timestamp -format "%Y-%m-%d" -gmt 1] +set time [clock format $timestamp -format "%H:%M:%S" -gmt 1] +set datetime "$date $time" +fossil amend $HASHINIT -date $datetime +test amend-date-1.1 {[string match "*hash:*$HASHINIT*$datetime*" $RESULT]} +fossil tag ls --raw $HASHINIT +test amend-date-1.2 {[string first "date=$datetime" $RESULT] != -1} +fossil timeline -n 1 +test amend-date-1.3 {[string match "*Timestamp*$date*$time*" $RESULT]} +set badformats { + "%+" + "%Y-%m-%d %H:%M%:%S %Z" + "%d/%m/%Y %H:%M%:%S %Z" + "%d/%m/%Y %H:%M%:%S" + "%d/%m/%Y" +} +set sc 0 +foreach badformat $badformats { + incr sc + set datetime [clock format $timestamp -format $badformat -gmt 1] + fossil amend $HASHINIT -date $datetime -expectError + test amend-date-2.$sc {[string first "YYYY-MM-DD HH:MM:SS" $RESULT] != -1} +} + +######################################## +# Test: -hide # +######################################## +set HASHH HASHH +fossil revert +fossil update trunk +fossil branch new tohide current +if {![uuid_from_branch $RESULT HASHH]} { + test amend-hide-setup false +} +fossil amend $HASHH -hide +test amend-hide-1.1 {[string match "*hash:*$HASHH*" $RESULT]} +fossil tag ls --raw $HASHH +test amend-hide-1.2 {[string first "hidden" $RESULT] != -1} +fossil timeline -n 1 +test amend-hide-1.3 {[string match {*Add*propagating*"hidden".*} $RESULT]} + +######################################## +# Test: -close # +######################################## +set HASHC HASHC +fossil branch new cllf $HASH +if {![uuid_from_branch $RESULT HASHC]} { + test amend-close.setup false +} +fossil update $HASHC +fossil amend $HASHC -close +test amend-close-1.1.a {[string match "*hash:*$HASHC*" $RESULT]} +test amend-close-1.1.b { + [string match "*comment:*Create*new*branch*named*\"cllf\"*" $RESULT] +} +fossil tag ls --raw $HASHC +test amend-close-1.2 {[string first "closed" $RESULT] != -1} +fossil timeline -n 1 +test amend-close-1.3 {[string match {*Mark*"Closed".*} $RESULT]} +write_file datafile "cllf" +fossil commit -m "should fail" -expectError +test amend-close-2 {[string first "closed leaf" $RESULT] != -1} + +set HASH3 HASH3 +fossil revert +fossil update trunk +write_file datafile "cb" +fossil commit -m "closed-branch" --branch "closebranch" +if {![uuid_from_commit $RESULT HASH3]} { + test amend-close-3.setup false +} +write_file datafile "b1" +fossil commit -m "m1" +write_file datafile "b2" +fossil commit -m "m2" +fossil amend $HASH3 --close +test amend-close-3.1 {[string match "*hash:*$HASH3*" $RESULT]} +fossil tag ls --raw current +test amend-close-3.2 {[string first "closed" $RESULT] != -1} +fossil timeline -n 1 +test amend-close-3.3 { + [string match "*Add*propagating*\"closed\".*" $RESULT] +} +write_file datafile "changed" +fossil commit -m "should fail" -expectError +test amend-close-3.4 {[string first "closed leaf" $RESULT] != -1} + +######################################## +# Test: -tag/-cancel # +######################################## +set tagtests { + tagged tagged + {000000 lower Upper alpha 0alpha} {000000 0alpha Upper alpha lower} +} +set tc 0 +foreach {tagt result} $tagtests { + incr tc + set tags {} + set cancels {} + set t1exp [join $result ", "] + set t2exp "*" + set t3exp "*" + set t5exp "*" + foreach tag $tagt { + lappend tags -tag $tag + lappend cancels -cancel $tag + } + foreach res $result { + append t3exp "Add*tag*\"$res\".*" + append t5exp "Cancel*tag*\"$res\".*" + } + foreach res [lsort -nocase $result] { + append t2exp "sym-$res*" + } + eval fossil amend $HASH $tags + test amend-tag-$tc.1 {[string match "*hash:*$HASH*tags:*$t1exp*" $RESULT]} + fossil tag ls --raw $HASH + test amend-tag-$tc.2 {[string match $t2exp $RESULT]} + fossil timeline -n 1 + test amend-tag-$tc.3 {[string match $t3exp $RESULT]} + eval fossil amend $HASH $cancels + test amend-tag-$tc.4 {![string match "*tags:*$t1exp*" $RESULT]} + fossil timeline -n 1 + test amend-tag-$tc.5 {[string match $t5exp $RESULT]} +} + +######################################## +# Test: -comment # +######################################## +proc prep-test {comment content} { + global HASH RESULT + + fossil revert + fossil update trunk + write_file datafile $comment + fossil commit -m $content + if {![uuid_from_commit $RESULT HASH]} { + set HASH "" + } +} + +proc test-comment {name HASH comment} { + global VERBOSE RESULT + + test amend-comment-$name.1 { + [string match "*hash:*$HASH*comment:*$comment*" $RESULT] + } + fossil timeline -n 1 + if {[artifact_from_timeline $RESULT artid]} { + fossil artifact $artid + test amend-comment-$name.2 { + [string match "*T +comment $HASH* *[manifest_comment $comment]*" $RESULT] + } + } else { + if {$VERBOSE} { protOut "No artifact found in timeline output: $RESULT" } + test amend-comment-$name.2 false + } + fossil timeline -n 1 + test amend-comment-$name.3 { + [string match "*[short_uuid $HASH]*Edit*check-in*comment.*" $RESULT] + } + fossil info $HASH + test amend-comment-$name.4 { + [string match "*hash:*$HASH*comment:*$comment*" $RESULT] + } +} + +prep-test "revision 1" "revision 1" +fossil amend $HASH -comment "revised revision 1" +test-comment 1 $HASH "revised revision 1" + +prep-test "revision 2" "revision 2" +fossil amend $HASH -m "revised revision 2 with -m" +test-comment 2 $HASH "revised revision 2 with -m" + +prep-test "revision 3" "revision 3" +write_file commitmsg "revision 3 revised" +fossil amend $HASH -message-file commitmsg +test-comment 3 $HASH "revision 3 revised" + +prep-test "revision 4" "revision 4" +write_file commitmsg "revision 4 revised with -M" +fossil amend $HASH -M commitmsg +test-comment 4 $HASH "revision 4 revised with -M" + +prep-test "final comment" "final content" +if {[catch {exec which ed} result] == 0} { + fossil settings editor "ed -s" + set comment "interactive edited comment" + fossil_maybe_answer "a\n$comment\n.\nw\nq\n" amend $HASH --edit-comment + test-comment 5 $HASH $comment +} + +######################################## +# Test: NULL hash # +######################################## +fossil amend {} -close -expectError +test amend-null-uuid {$CODE && [string first "no such check-in" $RESULT] != -1} + +############################################################################### + +test_cleanup diff --git a/test/clean.test b/test/clean.test new file mode 100644 index 0000000..d1b77d0 --- /dev/null +++ b/test/clean.test @@ -0,0 +1,193 @@ +# +# Copyright (c) 2015 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the "clean" command, including the ability to undo it. +# + +test_setup + +############################################################################### + +fossil extra +test clean-0 {[normalize_result] eq {}} + +############################################################################### + +write_file f1 "f1 line" +fossil add f1 +fossil commit -m "base file" +fossil ls +test clean-1 {[normalize_result] eq {f1}} + +############################################################################### + +fossil extra +test clean-2 {[normalize_result] eq {}} + +############################################################################### + +write_file f2 "f2 line" +fossil extra +test clean-3 {[normalize_result] eq {f2}} + +############################################################################### + +# clean w/undo enabled, should not prompt, 1 file < 10MiB +fossil clean +test clean-4 {[normalize_result] eq \ +{"fossil undo" is available to undo changes to the working checkout.}} + +############################################################################### + +fossil extra +test clean-5 {[normalize_result] eq {}} + +############################################################################### + +fossil undo +test clean-6 {[normalize_result] eq {NEW f2}} +test clean-7 {[read_file f2] eq "f2 line"} + +############################################################################### + +fossil extra +test clean-8 {[normalize_result] eq {f2}} + +############################################################################### + +write_file f3 [string repeat ABCDEFGHIJK 1048576] +fossil extra +test clean-9 {[normalize_result] eq {f2 +f3}} + +############################################################################### + +# clean w/undo enabled, no prompt, 1 file < 10MiB, 1 file > 10MiB +fossil clean --no-prompt +test clean-10 {[normalize_result] eq \ +{"fossil undo" is available to undo changes to the working checkout.}} + +############################################################################### + +fossil extra +test clean-11 {[normalize_result] eq {f3}} + +############################################################################### + +fossil undo +test clean-12 {[normalize_result] eq {NEW f2}} +test clean-13 {[read_file f2] eq "f2 line"} +test clean-14 {[read_file f3] eq [string repeat ABCDEFGHIJK 1048576]} + +############################################################################### + +fossil extra +test clean-15 {[normalize_result] eq {f2 +f3}} + +############################################################################### + +# clean w/undo enabled, force, 1 file < 10MiB, 1 file > 10MiB +fossil clean --force +test clean-16 {[normalize_result] eq \ +{"fossil undo" is available to undo changes to the working checkout.}} + +############################################################################### + +fossil extra +test clean-17 {[normalize_result] eq {}} + +############################################################################### + +fossil undo +test clean-18 {[normalize_result] eq {NEW f2}} +test clean-19 {[read_file f2] eq "f2 line"} + +############################################################################### + +write_file f4 [string repeat KJIHGFEDCBA 1048576] +fossil extra +test clean-20 {[normalize_result] eq {f2 +f4}} + +############################################################################### + +# clean w/undo disabled, no prompt, 1 file < 10MiB, 1 file > 10MiB +fossil clean --disable-undo --no-prompt +test clean-21 {[normalize_result] eq {}} + +############################################################################### + +fossil extra +test clean-22 {[normalize_result] eq {f2 +f4}} + +############################################################################### + +fossil undo -expectError +test clean-23 {[normalize_result] eq {nothing to undo}} + +############################################################################### + +# clean w/undo disabled, force, 1 file < 10MiB, 1 file > 10MiB +fossil clean --disable-undo --force +test clean-24 {[normalize_result] eq {}} + +############################################################################### + +fossil extra +test clean-25 {[normalize_result] eq {}} + +############################################################################### + +fossil undo -expectError +test clean-26 {[normalize_result] eq {nothing to undo}} + +############################################################################### + +write_file f5 "f5 line" +fossil extra +test clean-27 {[normalize_result] eq {f5}} + +############################################################################### + +# clean w/undo disabled, should prompt, 1 file < 10MiB +fossil_maybe_answer Y clean --disable-undo +test clean-28 {[normalize_result] eq \ +{WARNING: Deletion of this file will not be undoable via the 'undo' + command because undo is disabled for this operation. + +Remove unmanaged file "f5" (a=all/y/N)?}} + +############################################################################### + +fossil extra +test clean-29 {[normalize_result] eq {}} + +############################################################################### + +fossil undo -expectError +test clean-30 {[normalize_result] eq {nothing to undo}} + +############################################################################### + +fossil extra +test clean-31 {[normalize_result] eq {}} + +############################################################################### + +test_cleanup diff --git a/test/cmdline.test b/test/cmdline.test new file mode 100644 index 0000000..ff1c595 --- /dev/null +++ b/test/cmdline.test @@ -0,0 +1,54 @@ +# +# Copyright (c) 2012 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Test command line parsing +# + +test_setup "" + +proc cmd-line {usefile testname args} { + set i 1 + foreach {cmdline result} $args { + if {$usefile} { + set cmdlinefile [file join \ + [getTemporaryPath] fossil-cmd-line-$testname.txt] + + write_file $cmdlinefile $cmdline + fossil test-echo --args $cmdlinefile + file delete $cmdlinefile + } else { + fossil test-echo $cmdline + } + + test cmd-line-$testname.$i \ + {[lrange [split $::RESULT \n] 3 end]=="\{argv\[2\] = \[$result\]\}"} + + incr i + } +} + +cmd-line false 100 abc abc a\"bc a\"bc \"abc\" \"abc\" + +# +# NOTE: Use an --args file on Windows to avoid unwanted glob expansion +# from MinGW and/or the MSVCRT. +# +cmd-line $is_windows 101 * * *.* *.* + +############################################################################### + +test_cleanup diff --git a/test/commit-warning.test b/test/commit-warning.test new file mode 100644 index 0000000..8f9c455 --- /dev/null +++ b/test/commit-warning.test @@ -0,0 +1,166 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# The focus of this file is to test pre-commit warnings. +# + +test_setup + +# binary +write_file binary "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + +# text with CRLF lines +write_file crlf.txt [subst -nocommands -novariables \ +{ordinary text\r +cariage returns and line feeds\r +on several lines\r\n}] + +# text with mixed line endings +write_file cr-only.txt "AAA\rBBB\rCCC\r" +write_file cr-lf-crlf.txt "AAA\rBBB\nCCC\r\n" + +# unix plain text includes the empty file by generalization +write_file empty "" +write_file plain.txt { +Lorem ipsum +dolor sic amet +} + +# try long lines +set a3 "abcdefgh" +set a4 $a3$a3 +set a5 $a4$a4 +set a6 $a5$a5 +write_file line-0064 "$a6\n" +set a7 $a6$a6 +set a8 $a7$a7 +set a9 $a8$a8 +set a10 $a9$a9 +write_file line-1024 "$a10\n" +set a11 $a10$a10 +write_file line-2048 "$a11\n" +set a12 $a11$a11 +write_file line-4096 "$a12\n" +set a13 $a12$a12 +write_file line-8192 "$a13\n" +set a14 $a13$a13 +write_file line-16K "$a14\n" +set a15 $a14$a14 +write_file line-32K "$a15\n" +set a16 $a15$a15 +write_file line-64K "$a16\n" + +# UTF-8 extends 7-bit ASCII using bytes 80 and above to encode +# larger character codes. Unicode uses U+0 through U+10FFFF only, +# with U+D800 through U+DFFF reserved for surrogate pairs. +# UTF-8 is valid if it is the shortest possible coding, encodes a +# valid Unicode code point. But it's complicated. +write_file utf-mod-c0-80 "11 bit NUL:\xC0\x80 is sometimes ok\n" +write_file utf-bad-e0-80-80 "16 bit NUL:\xE0\x80\x80 is bad\n" +write_file utf-bad-f0-80-80-80 "21 bit NUL:\xF0\x80\x80\x80 is bad\n" +write_file utf-bad-f8-80-80-80-80 "26 bit NUL:\xF8\x80\x80\x80\x80 is bad\n" +write_file utf-bad-fc-80-80-80-80-80 "31 bit NUL:\xFC\x80\x80\x80\x80\x80 is bad\n" +write_file utf-bad-fe-80-80-80-80-80-80 "36 bit NUL:\xFC\x80\x80\x80\x80\x80 is bad\n" +write_file utf-bad-c0-81 "overlong SOH:\xC0\x81 is bad\n" +write_file utf-bad-c0-bf "overlong '?':\xC0\xBF is bad\n" +write_file utf-bad-c1-bf "overlong DEL:\xC1\xBF is bad\n" +write_file utf-bad-f4-90-80-80 "U+110000 not allowed:\xF4\x90\x80 not unicode\n" +write_file utf-bad-f9-80-80-80-80 "U+2000000 not allowed:\xF9\x80\x80\x80\x80 not unicode\n" +write_file utf-bad-ff "no byte FF:\xFF\n" +write_file utf-ill16-lead "lead surrogate U+D800:\xED\xA0\x80 is ill formed\n" +write_file utf-ill16-trail "trail surrogate U+DC00:\xED\xB0\x80 is ill formed\n" +write_file utf-ill16-pair "surrogate pair U+10000:\xED\xA0\x80\xED\xB0\x80 is ill formed\n" +set emoji "micro-smile \xC2\xB5\xE2\x98\xBA\npale facepalm \xF0\x9F\xA4\xA6\xF0\x9F\x8F\xBB\n" +protOut $emoji +write_file utf-8-emoji $emoji +write_file utf-8-bom-emoji "\xef\xbb\xbf$emoji" + +# UTF-16 uses 16-bit values to cover all valid unicode code points +# from U+0 to U+10FFFF, using surrogate pairs to escape the BMP. +# Interchange require knowing (and preserving) byte order. +set hello16LE "h\x00e\x00l\x00l\x00o\x00\n\x00" +set hello16BE "\x00h\x00e\x00l\x00l\x00o\x00\n" +write_file utf-16le-hello $hello16LE +write_file utf-16be-hello $hello16BE +set bomLE "\xff\xfe" +set bomBE "\xfe\xff" +write_file utf-16le-bomle-hello "$bomLE$hello16LE" +write_file utf-16be-bombe-hello "$bomBE$hello16BE" +write_file utf-16le-bombe-hello "$bomBE$hello16LE" +write_file utf-16be-bomle-hello "$bomLE$hello16BE" +set le16 [read_file [file join $testdir utf16le.txt]] +set be16 [read_file [file join $testdir utf16be.txt]] +write_file utf-16le.txt $le16 +write_file utf-16be.txt $be16 +write_file utf-nobom-16le.txt [string range $le16 2 end] +write_file utf-nobom-16be.txt [string range $be16 2 end] +#write_file [file join $::env(TEMP) utf-nobom-16le.txt] [string range $le16 2 end] +#write_file [file join $::env(TEMP) utf-nobom-16be.txt] [string range $be16 2 end] + +# make all the test files known to fossil, then test +fossil addremove +fossil test-commit-warning --no-settings -v +test pre-commit-warnings-1 {[normalize_result] eq \ + [subst -nocommands -novariables [string trim { +1\tbinary\tbinary data +1\tcr-lf-crlf.txt\tmixed line endings +1\tcr-only.txt\tCR line endings +1\tcrlf.txt\tCR/LF line endings +0\tempty\t +0\tline-0064\t +0\tline-1024\t +0\tline-16K\t +0\tline-2048\t +1\tline-32K\tlong lines +0\tline-4096\t +1\tline-64K\tlong lines +0\tline-8192\t +0\tplain.txt\t +1\tutf-16be-bombe-hello\tUnicode +1\tutf-16be-bomle-hello\tUnicode +1\tutf-16be-hello\tbinary data +1\tutf-16be.txt\tUnicode +1\tutf-16le-bombe-hello\tUnicode +1\tutf-16le-bomle-hello\tUnicode +1\tutf-16le-hello\tbinary data +1\tutf-16le.txt\tUnicode +0\tutf-8-bom-emoji\t +0\tutf-8-emoji\t +1\tutf-bad-c0-81\tinvalid UTF-8 +1\tutf-bad-c0-bf\tinvalid UTF-8 +1\tutf-bad-c1-bf\tinvalid UTF-8 +1\tutf-bad-e0-80-80\tinvalid UTF-8 +1\tutf-bad-f0-80-80-80\tinvalid UTF-8 +1\tutf-bad-f4-90-80-80\tinvalid UTF-8 +1\tutf-bad-f8-80-80-80-80\tinvalid UTF-8 +1\tutf-bad-f9-80-80-80-80\tinvalid UTF-8 +1\tutf-bad-fc-80-80-80-80-80\tinvalid UTF-8 +1\tutf-bad-fe-80-80-80-80-80-80\tinvalid UTF-8 +1\tutf-bad-ff\tinvalid UTF-8 +0\tutf-ill16-lead\t +0\tutf-ill16-pair\t +0\tutf-ill16-trail\t +0\tutf-mod-c0-80\t +1\tutf-nobom-16be.txt\tbinary data +1\tutf-nobom-16le.txt\tbinary data +1}]]} + + +############################################################################### + + +test_cleanup diff --git a/test/contains-selector.test b/test/contains-selector.test new file mode 100644 index 0000000..1f971f1 --- /dev/null +++ b/test/contains-selector.test @@ -0,0 +1,55 @@ +# +# Copyright (c) 2015 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Test containsSelector() function in src/style.c +# + +test_setup "" + +proc contains-selector {testId css selectorResultMap} { + set css [string trim $css] + set filename [file join $::tempPath compare-selector.css] + set fh [open $filename w] + puts -nonewline $fh $css + close $fh + foreach {selector found} $selectorResultMap { + set expected "$selector [expr {$found ? "found" : "not found"}]" + set result [fossil test-contains-selector $filename $selector] + test "contains-selector $testId $selector" {$result eq $expected} + } + file delete $filename +} + +contains-selector 1 { + .a.b {} + .c .de {} + /* comment */ + .c .d, .e /* comment */ {} +} { + .a 0 + .b 0 + .a.b 1 + .c 0 + .d 0 + {.c.d} 0 + {.c .d} 1 + .e 1 +} + +############################################################################### + +test_cleanup diff --git a/test/csp1.html b/test/csp1.html new file mode 100644 index 0000000..07b8d64 --- /dev/null +++ b/test/csp1.html @@ -0,0 +1,18 @@ + + + +Title: Content Security Policy Test + + +

Content Security Policy Test

+ +

If the content-security-policy is ineffective, a pop-up dialog +box will appears. If there is no dialog box, then CSP is working +correctly.

+ + + + +

As a double-check, open the Developer Console in your web-browser +and verify that two CSP violations were detected and blocked.

+ diff --git a/test/delta1.test b/test/delta1.test new file mode 100644 index 0000000..82d7936 --- /dev/null +++ b/test/delta1.test @@ -0,0 +1,60 @@ +# +# Copyright (c) 2006 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the delta mechanism. +# + +test_setup "" + +# Use test script files as the basis for this test. +# +# For each test, copy the file intact to "./t1". Make +# some random changes in "./t2". Then call test-delta on the +# two files to make sure that deltas between these two files +# work properly. +# +set filelist [lsort [glob $testdir/*]] +foreach f $filelist { + if {[file isdir $f]} continue + set base [file root [file tail $f]] + set f1 [read_file $f] + write_file t1 $f1 + for {set i 0} {$i<100} {incr i} { + write_file t2 [random_changes $f1 1 1 0 0.1] + fossil test-delta t1 t2 + test delta-$base-$i-1 {[normalize_result]=="ok"} + write_file t2 [random_changes $f1 1 1 0 0.2] + fossil test-delta t1 t2 + test delta-$base-$i-2 {[normalize_result]=="ok"} + write_file t2 [random_changes $f1 1 1 0 0.4] + fossil test-delta t1 t2 + test delta-$base-$i-3 {[normalize_result]=="ok"} + } +} + +set empties { "" "" "" a a "" } +set i 0 +foreach {f1 f2} $empties { + incr i + write_file t1 $f1 + write_file t2 $f2 + fossil test-delta t1 t2 + test delta-empty-$i {[normalize_result]=="ok"} +} +############################################################################### + +test_cleanup diff --git a/test/diff-test-1.wiki b/test/diff-test-1.wiki new file mode 100644 index 0000000..46ba4ba --- /dev/null +++ b/test/diff-test-1.wiki @@ -0,0 +1,60 @@ +Graph Test One + +This page contains list of URLs of interesting diffs. +Click on all URLs, one by one, to verify +the correct operation of the diff logic. +For correct testing, many of these require show-version-diffs +to be enabled in the [/setup_timeline|Timeline Display Preferences] +configuration page. + + * + Multiple edits on a single line. This is an SQLite version + update diff. It is a large diff and contains many other interesting + features. Scan the whole diff. + * Tricky alignment and multiple edits per line. + * Add a column to a table + * Column alignment with multibyte characters. + The edit of a line with multibyte characters is the first chunk. + * Large diff of sqlite3.c. This diff was very + slow prior to the performance enhancement change [9e15437e97]. + * + A difficult indentation change. UPDATE: Notice also the improved + multi-segment update marks on lines 122648 and 122763 on the new side. + * Inverse of the previous. + * Another tricky indentation. Notice especially + lines 59398 and 59407 on the left. + * Inverse of the previous. + * A complex change that is difficult to align, and + hence falls back to the "delete left and insert right" strategy. + * Inverse of the previous. + * sqlite3.c changes + that are difficult to align. + * sqlite3.c changes inverted. + * Lorem Ipsum in Greek. + * Lorem Ipsum in Greek inverted. + +External: + + * + Code indentation change. + * + A complex change (chunk 1) in which the alignment becomes so complex + that it is better for clarity to abandon it and just show the left + and right sides contiguously. + * + An indentation change. See especially lines 2313 and 2317 on the right, + that their green indentation addition is left-justified. diff --git a/test/diff.test b/test/diff.test new file mode 100644 index 0000000..4b02329 --- /dev/null +++ b/test/diff.test @@ -0,0 +1,162 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests for the diff command. +# + +require_no_open_checkout + +test_setup; set rootDir [file normalize [pwd]] + +################################### +# Tests of binary file detection. # +################################### + +file mkdir .fossil-settings +write_file [file join .fossil-settings binary-glob] "*" + +write_file file0.dat ""; # no content. +write_file file1.dat "test file 1 (one line no term)." +write_file file2.dat "test file 2 (NUL character).\0" +write_file file3.dat "test file 3 (long line).[string repeat x 32768]" +write_file file4.dat "test file 4 (long line).[string repeat y 32768]\ntwo" +write_file file5.dat "[string repeat z 32768]\ntest file 5 (long line)." + +fossil add $rootDir +fossil commit -m "c1" + +############################################################################### + +fossil ls +test diff-ls-1 {[normalize_result] eq \ +"file0.dat\nfile1.dat\nfile2.dat\nfile3.dat\nfile4.dat\nfile5.dat"} + +############################################################################### + +write_file file0.dat "\0" +fossil diff file0.dat + +test diff-file0-1 {[normalize_result] eq {Index: file0.dat +================================================================== +--- file0.dat ++++ file0.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file1.dat [string repeat z 32768] +fossil diff file1.dat + +test diff-file1-1 {[normalize_result] eq {Index: file1.dat +================================================================== +--- file1.dat ++++ file1.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file2.dat "test file 2 (no NUL character)." +fossil diff file2.dat + +test diff-file2-1 {[normalize_result] eq {Index: file2.dat +================================================================== +--- file2.dat ++++ file2.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file3.dat "test file 3 (not a long line)." +fossil diff file3.dat + +test diff-file3-1 {[normalize_result] eq {Index: file3.dat +================================================================== +--- file3.dat ++++ file3.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file4.dat "test file 4 (not a long line).\ntwo" +fossil diff file4.dat + +test diff-file4-1 {[normalize_result] eq {Index: file4.dat +================================================================== +--- file4.dat ++++ file4.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file5.dat "[string repeat 0 16]\ntest file 5 (not a long line)." +fossil diff file5.dat + +test diff-file5-1 {[normalize_result] eq {Index: file5.dat +================================================================== +--- file5.dat ++++ file5.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file6a.dat "{\n \"abc\": {\n \"def\": false,\n \"ghi\": false\n }\n}\n" +write_file file6b.dat "{\n \"abc\": {\n \"def\": false,\n \"ghi\": false\n },\n \"jkl\": {\n \"mno\": {\n \"pqr\": false\n }\n }\n}\n" +fossil xdiff -y -W 16 file6a.dat file6b.dat +test diff-file-6-1 {[normalize_result] eq {========== file6a.dat ===== versus ===== file6b.dat ===== + 1 { 1 { + 2 "abc": { 2 "abc": { + 3 "def": false, 3 "def": false, + 4 "ghi": false 4 "ghi": false + > 5 }, + > 6 "jkl": { + > 7 "mno": { + > 8 "pqr": false + > 9 } + 5 } 10 } + 6 } 11 }}} + +############################################################################### + +fossil rm file1.dat +fossil diff -v file1.dat + +test diff-deleted-file-1 {[normalize_result] eq {DELETED file1.dat +Index: file1.dat +================================================================== +--- file1.dat ++++ /dev/null +@@ -1,1 +0,0 @@ +-test file 1 (one line no term).}} + +############################################################################### + +write_file file6.dat "test file 6 (one line no term)." +fossil add file6.dat + +fossil diff -v file6.dat + +test diff-added-file-1 {[normalize_result] eq {ADDED file6.dat +Index: file6.dat +================================================================== +--- /dev/null ++++ file6.dat +@@ -0,0 +1,1 @@ ++test file 6 (one line no term).}} + +############################################################################### + +test_cleanup diff --git a/test/fake-editor.tcl b/test/fake-editor.tcl new file mode 100644 index 0000000..a363fb7 --- /dev/null +++ b/test/fake-editor.tcl @@ -0,0 +1,98 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# This is a fake text editor for use by tests. To customize its behavior, +# set the FAKE_EDITOR_SCRIPT environment variable prior to evaluating this +# script file. If FAKE_EDITOR_SCRIPT environment variable is not set, the +# default behavior will be used. The default behavior is to append the +# process identifier and the current time, in seconds, to the file data. +# + +if {![info exists argv] || [llength $argv] != 1} { + error "Usage: \"[info nameofexecutable]\" \"[info script]\" " +} + +############################################################################### + +proc makeBinaryChannel { channel } { + fconfigure $channel -encoding binary -translation binary +} + +proc readFile { fileName } { + set channel [open $fileName RDONLY] + makeBinaryChannel $channel + set result [read $channel] + close $channel + return $result +} + +proc writeFile { fileName data } { + set channel [open $fileName {WRONLY CREAT TRUNC}] + makeBinaryChannel $channel + puts -nonewline $channel $data + close $channel + return "" +} + +############################################################################### + +set fileName [lindex $argv 0] + +if {[regexp {^CYGWIN} $::tcl_platform(os)]} { + # Under Cygwin, we get a Windows path but must access using the unix path. + set fileName [exec cygpath --unix $fileName] +} + +if {[file exists $fileName]} { + set data [readFile $fileName] +} else { + set data "" +} + +############################################################################### + +if {[info exists env(FAKE_EDITOR_SCRIPT)]} { + # + # NOTE: If an error is caught while evaluating this script, catch + # it and return, which will also skip writing the (possibly + # modified) content back to the original file. + # + set script $env(FAKE_EDITOR_SCRIPT) + set code [catch $script error] + + if {$code != 0} { + if {[info exists env(FAKE_EDITOR_VERBOSE)]} { + if {[info exists errorInfo]} { + puts stdout "ERROR ($code): $errorInfo" + } else { + puts stdout "ERROR ($code): $error" + } + } + + return + } +} else { + # + # NOTE: The default behavior is to append the process identifier + # and the current time, in seconds, to the file data. + # + append data " " [pid] " " [clock seconds] +} + +############################################################################### + +writeFile $fileName $data diff --git a/test/file1.test b/test/file1.test new file mode 100644 index 0000000..501d1d5 --- /dev/null +++ b/test/file1.test @@ -0,0 +1,104 @@ +# +# Copyright (c) 2011 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# File utilities +# + +test_setup + +proc simplify-name {testname args} { + set i 1 + foreach {path result} $args { + fossil test-simplify-name $path + test simplify-name-$testname.$i {$::RESULT=="\[$path\] -> \[$result\]"} + incr i + } +} + +proc relative-name {testname args} { + set i 1 + foreach {subdir path result} $args { + fossil test-relative-name --chdir $subdir $path + test relative-name-$testname.$i {$::RESULT==$result} + incr i + } +} + +proc relative-tree-name {testname args} { + set i 1 + foreach {subdir path result} $args { + fossil test-tree-name --chdir $subdir $path + test relative-tree-name-$testname.$i {$::RESULT==$result} + incr i + } +} + +proc absolute-tree-name {testname args} { + set i 1 + foreach {subdir path result} $args { + fossil test-tree-name --chdir $subdir --absolute $path + test absolute-tree-name-$testname.$i {$::RESULT==$result} + incr i + } +} + +simplify-name 100 . . .// . .. .. ..///// .. +simplify-name 101 {} {} / / ///////// / ././././ . +simplify-name 102 x x /x /x ///x //x +simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b +simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c +simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y +simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y +simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y + +if {$::tcl_platform(os)=="Windows NT"} { + simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {} + simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {} +} + +# This is needed because we are now running outside of the Fossil checkout. +file mkdir file1; set savedPwd [pwd]; cd file1 + +# Those directories are only needed for the testcase being able to "--chdir" to it. +file mkdir test1 +file mkdir test1/test2 + +relative-name 100 . . . test1 [pwd] .. test1 [pwd]/ .. test1 [pwd]/test ../test +relative-name 101 test1/test2 [pwd] ../.. test1/test2 [pwd]/ ../.. test1/test2 [pwd]/test ../../test +relative-name 102 test1 [pwd]/test ../test . [pwd]/file1 ./file1 . [pwd]/file1/file2 ./file1/file2 +relative-name 103 . [pwd] . + +relative-tree-name 100 . . file1 test1 [pwd] file1 test1 [pwd]/ file1 test1 [pwd]/test file1/test +relative-tree-name 101 test1/test2 [pwd] file1 test1/test2 [pwd]/ file1 test1/test2 [pwd]/test file1/test +relative-tree-name 102 test1 [pwd]/test file1/test . [pwd]/file1 file1/file1 . [pwd]/file1/file2 file1/file1/file2 +relative-tree-name 103 . [pwd] file1 + +set dirname [file normalize [file dirname [pwd]]] + +absolute-tree-name 100 . . $dirname test1 [pwd] [pwd] test1 [pwd]/ $dirname/file1 test1 [pwd]/test $dirname/file1/test +absolute-tree-name 101 test1/test2 [pwd] $dirname/file1 test1/test2 [pwd]/ $dirname/file1 test1/test2 [pwd]/test $dirname/file1/test +absolute-tree-name 102 test1 [pwd]/test $dirname/file1/test . [pwd]/file1 $dirname/file1/file1 . [pwd]/file1/file2 $dirname/file1/file1/file2 +absolute-tree-name 103 . [pwd] $dirname/file1 + +catch {file delete test1/test2} +catch {file delete test1} + +if {[info exists savedPwd]} {cd $savedPwd; unset savedPwd} + +############################################################################### + +test_cleanup diff --git a/test/fileStat.th1 b/test/fileStat.th1 new file mode 100644 index 0000000..071b587 --- /dev/null +++ b/test/fileStat.th1 @@ -0,0 +1,102 @@ + + proc doSomeTclSetup {} { + # + # NOTE: Copy repository file name to the Tcl interpreter. This is + # done first (once) because it will be necessary for almost + # everything else later on. + # + tclInvoke set repository [repository] + + # + # NOTE: Create some procedures in the Tcl interpreter to perform + # useful operations. This could also do things like load + # packages, etc. + # + tclEval { + # + # NOTE: Returns an [exec] command for Fossil, using the provided + # sub-command and arguments, suitable for use with [eval] + # or [catch]. + # + proc getFossilCommand { repository user args } { + global env + + lappend result exec [info nameofexecutable] + + if {[info exists env(GATEWAY_INTERFACE)]} then { + # + # NOTE: This option is required when calling + # out to the Fossil executable from a + # CGI process. + # + lappend result -nocgi + } + + eval lappend result $args + + if {[string length $repository] > 0} then { + # + # NOTE: This is almost certainly required + # when calling out to the Fossil + # executable on the server because + # there is almost never an open + # checkout. + # + lappend result -R $repository + } + + if {[string length $user] > 0} then { + lappend result -U $user + } + + # th1Eval [list html $result
] + + return $result + } + } + } + + proc getLatestTrunkCheckIn {} { + tclEval { + # + # NOTE: Get the unique Id of the latest check-in on trunk. + # + return [lindex [regexp -line -inline -nocase -- \ + {^(?:uuid|hash):\s+([0-9A-F]{40}) } [eval [getFossilCommand \ + $repository "" info trunk]]] end] + } + } + + proc theSumOfAllFiles { id } { + # + # NOTE: Copy check-in Id value to the Tcl interpreter. + # + tclInvoke set id $id + + tclEval { + set count 0 + + foreach line [split [eval [getFossilCommand \ + $repository "" artifact $id]] \n] { + # + # NOTE: Is this an "F" (file) card? + # + if {[string range $line 0 1] eq "F "} then { + incr count + } + } + + return $count + } + } + + doSomeTclSetup; # perform some extra setup for the Tcl interpreter. + + set checkIn [getLatestTrunkCheckIn] + set totalFiles [theSumOfAllFiles $checkIn] +
+ +
+As of trunk check-in decorate \[$checkIn\], this +repository contains html $totalFiles files. +
diff --git a/test/fileage-test-1.wiki b/test/fileage-test-1.wiki new file mode 100644 index 0000000..f556891 --- /dev/null +++ b/test/fileage-test-1.wiki @@ -0,0 +1,14 @@ + +This page contains URLs for file-age computations that have given +trouble in the past. Shift-click on on the links, one-by-one, to verify +that the current implementation works correctly: + + * [/fileage?name=c9df0dcdaa402] - Verify that the many + execute permission changes that occurred about 24 hours before + check-in c9df0dcdaa402 do not appear as file changes. + + * [/tree?ci=c9df0dcdaa40&mtime=0&type=tree] - Verify that all + three skin files (css.txt, footer.txt, and header.txt) appear + in all of the skin/*/ folders. + + * On both of the above, check for excessive computation time. diff --git a/test/glob.test b/test/glob.test new file mode 100644 index 0000000..1b817af --- /dev/null +++ b/test/glob.test @@ -0,0 +1,190 @@ +# +# Copyright (c) 2013 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Test glob pattern parsing +# + +test_setup "" + +proc glob-parse {testname args} { + set i 1 + foreach {pattern string result} $args { + fossil test-glob $pattern $string + test glob-parse-$testname.$i {$::RESULT eq $result} + incr i + } +} + +glob-parse 100 test test [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'test') +pattern[0] = [test] +1 1 test}] + +glob-parse 101 "one two" one [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'one' OR x GLOB 'two') +pattern[0] = [one] +pattern[1] = [two] +1 1 one}] + +glob-parse 102 t* test [string map [list \r\n \n] \ +{SQL expression: (x GLOB 't*') +pattern[0] = [t*] +1 1 test}] + +glob-parse 103 "o* two" one [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o*' OR x GLOB 'two') +pattern[0] = [o*] +pattern[1] = [two] +1 1 one}] + +glob-parse 104 {"o* two" "three four"} "one two" [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* two' OR x GLOB 'three four') +pattern[0] = [o* two] +pattern[1] = [three four] +1 1 one two}] + +glob-parse 105 {"o* two" "three four"} "two one" [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* two' OR x GLOB 'three four') +pattern[0] = [o* two] +pattern[1] = [three four] +0 0 two one}] + +glob-parse 106 "\"o*\ntwo\" \"three\nfour\"" "one\ntwo" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* +two' OR x GLOB 'three +four') +pattern[0] = [o* +two] +pattern[1] = [three +four] +1 1 one +two}] + +glob-parse 107 "\"o*\ntwo\" \"three\nfour\"" "two\none" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* +two' OR x GLOB 'three +four') +pattern[0] = [o* +two] +pattern[1] = [three +four] +0 0 two +one}] + +glob-parse 108 "\"o*\rtwo\" \"three\rfour\"" "one\rtwo" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* +two' OR x GLOB 'three +four') +pattern[0] = [o* +two] +pattern[1] = [three +four] +1 1 one +two}] + +glob-parse 109 "\"o*\rtwo\" \"three\rfour\"" "two\rone" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* +two' OR x GLOB 'three +four') +pattern[0] = [o* +two] +pattern[1] = [three +four] +0 0 two +one}] + +glob-parse 110 "'o*\ntwo' 'three\nfour'" "one\ntwo" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* +two' OR x GLOB 'three +four') +pattern[0] = [o* +two] +pattern[1] = [three +four] +1 1 one +two}] + +glob-parse 111 "'o*\ntwo' 'three\nfour'" "two\none" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o* +two' OR x GLOB 'three +four') +pattern[0] = [o* +two] +pattern[1] = [three +four] +0 0 two +one}] + +glob-parse 112 "\"'o*' 'two'\" \"'three' 'four'\"" "'one' 'two'" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''') +pattern[0] = ['o*' 'two'] +pattern[1] = ['three' 'four'] +1 1 'one' 'two'}] + +glob-parse 113 "\"'o*' 'two'\" \"'three' 'four'\"" "two one" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB '''o*'' ''two''' OR x GLOB '''three'' ''four''') +pattern[0] = ['o*' 'two'] +pattern[1] = ['three' 'four'] +0 0 two one}] + +glob-parse 114 o*,two one [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o*' OR x GLOB 'two') +pattern[0] = [o*] +pattern[1] = [two] +1 1 one}] + +glob-parse 115 "o*,two three,four" "one two" [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o*' OR x GLOB 'two' OR x GLOB 'three' OR x GLOB 'four') +pattern[0] = [o*] +pattern[1] = [two] +pattern[2] = [three] +pattern[3] = [four] +1 1 one two}] + +glob-parse 116 'o*,two' one [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o*,two') +pattern[0] = [o*,two] +0 0 one}] + +glob-parse 117 'o*,two' one,two [string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o*,two') +pattern[0] = [o*,two] +1 1 one,two}] + +glob-parse 118 "'o*,two three,four'" "one two three,four" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o*,two three,four') +pattern[0] = [o*,two three,four] +0 0 one two three,four}] + +glob-parse 119 "'o*,two three,four'" "one,two three,four" \ +[string map [list \r\n \n] \ +{SQL expression: (x GLOB 'o*,two three,four') +pattern[0] = [o*,two three,four] +1 1 one,two three,four}] + +############################################################################### + +test_cleanup diff --git a/test/graph-test-1.wiki b/test/graph-test-1.wiki new file mode 100644 index 0000000..056b829 --- /dev/null +++ b/test/graph-test-1.wiki @@ -0,0 +1,119 @@ +Graph Test One + +This page contains examples a list of URLs of timelines with +interesting graphs. Click on all URLs, one by one, to verify +the correct operation of the graph drawing logic. + + * + 20-element timeline, check-ins only, before 2010-11-08 + * + 20-element timeline, check-ins only, no graph, before 2010-11-08 + * + 20-element timeline, check-ins only, file changes, before 2010-11-08 + * + 40-element timeline, check-ins only, before 2010-11-08 + * + 1000-element timeline, check-ins only, before 2010-11-08 + * + 10-elements circa 2010-11-07 10:23:00, with dividers + * + 10-elements circa 2010-11-07 10:23:00, without dividers + * + Parents and children of check-in 3ea66260b5555 + * multiple merge descenders from the penultimate node. + + * + multiple branch risers. + * + multiple branch risers, n=18. + * + multiple branch risers, n=9. + * + Experimental branch with related check-ins. + * + Experimental branch with merge-ins only. + * + Experimental branch check-ins only. + * + Check-ins tagged "release" and related check-ins + * + Check-ins tagged "release" and merge-ins + * + Only check-ins tagged "release" + * + History of source file "Makefile". + * + 20 elements after 1970-01-01. + * + All check-ins - a huge graph. + * + This malformed commit has a + merge parent which is not a valid checkin. + * + From e663bac6f7 to a298a0e2f9 by shortest path. + * + From e663bac6f7 to a298a0e2f9 without merge links. + * + Common ancestor path of e663bac6f7 to a298a0e2f9. + * + Merge on the same branch does not result in a leaf. + + * + This timeline has a hidden commit. Click Unhide to reveal. + * Isolated check-ins. + * Single branch raiser from bottom of page + up to checkins 057e4b and d3cc6d + * Branch riser comes from the bottom of the screen + * Branch risers comes from the bottom of the + screen, not from the andygoth-crlf branch. + * Check-in 2de15c8e has merge arrows from two + different trunk check-ins. One of the merge risers also branches + to check-in ea7f3297 + * + Cherrypick merge arrows + * Branch + 1.37 with cherry-pick merges from trunk. + * + Single check-in takes both a full merge and a cherrypick merge + * + Mixed merge arrow, partly fully and partly cherrypick + * + Mixed merge arrow to bottom of screen. + * + A fork on trunk keeps the longest chain of child nodes directly + above the fork and the shorter chain off to the side. + * + The "jan-manifest-tags" branch containing a non-trunk fork + * + The "diff-eolws" branch containing a non-trunk fork + * + All forks + * All leaves + +External: + + * Timewarp due to a mis-configured system clock. + * Show all three separate deletions of "id.test". + (Scroll down for the third deletion.) + * Merge arrows to the left and to the right + * Previous, with a scrunched graph + * Previous, with a severely scrunched graph + * The "wal" branch SQLite repository, containing + multiple non-trunk forks. diff --git a/test/graph-test-2.md b/test/graph-test-2.md new file mode 100644 index 0000000..fb8eead --- /dev/null +++ b/test/graph-test-2.md @@ -0,0 +1,72 @@ +# Graph Test Cases + +There are test cases for the merge-riser coalescing logic that +was added on 2020-06-08. + + * [e19cfba5373369b](/info/e19cfba5373369b?diff=0) + * [c779b6890464cae](/info/c779b6890464cae?diff=0) + * [eed3946bd92a499](/info/eed3946bd92a499?diff=0) + * [9e1fa626e47f147](/info/9e1fa626e47f147?diff=0) + * [68bd2e7bedb8d05](/info/68bd2e7bedb8d05?diff=0) + * [8ac66ef33b464d2](/info/8ac66ef33b464d2?diff=0) + * [ef6979eac9abded](/info/ef6979eac9abded?diff=0) + * [7766e689926c703](/info/7766e689926c703?diff=0) + * [642f4dcfa24f1f9](/info/642f4dcfa24f1f9?diff=0) + * [3ea66260b5555d2](/info/3ea66260b5555d2?diff=0) + * [66ae70a54b20656](/info/66ae70a54b20656?diff=0) + * [b0f2a0ac53926c9](/info/b0f2a0ac53926c9?diff=0) + * [303e7af7c31866c](/info/303e7af7c31866c?diff=0) + * [b31afcc2cab1dc4](/info/b31afcc2cab1dc4?diff=0) + * [1a164e5fb76a46b](/info/1a164e5fb76a46b?diff=0) + * [f325b2343e6a18f](/info/f325b2343e6a18f?diff=0) + * [2d75e87b760c0a9](/info/2d75e87b760c0a9?diff=0) + * [76442af7e13267b](/info/76442af7e13267b?diff=0) + + +The list above was generated by the following script: + +~~~~~ +.mode list +SELECT printf(' * [%s](/info/%s?diff=0)', hash, hash) FROM ( + SELECT count(*) AS cnt, sum(cherrypick=1) AS cp, sum(cherrypick=0) AS n, + (SELECT substr(uuid,1,15) FROM blob WHERE rid=cid) AS hash + FROM ( + SELECT cid, 0 AS cherrypick FROM plink WHERE NOT isprim + UNION ALL + SELECT childid, 1 FROM cherrypick + ) + GROUP BY cid + HAVING (cp>0 AND n>0) OR cp>3 OR n>2 + ORDER BY cnt +); +~~~~~ + +Similar links to the SQLite repository: + + * [7f72fc4f47445a2](https://sqlite.org/src/info/7f72fc4f47445a2?diff=0) + * [db2935473eab91c](https://sqlite.org/src/info/db2935473eab91c?diff=0) + * [a56506b9387a067](https://sqlite.org/src/info/a56506b9387a067?diff=0) + * [d59567dda231e7f](https://sqlite.org/src/info/d59567dda231e7f?diff=0) + * [2b750b0f74e5a11](https://sqlite.org/src/info/2b750b0f74e5a11?diff=0) + * [c697d2f83c2d8ea](https://sqlite.org/src/info/c697d2f83c2d8ea?diff=0) + * [b330c7ff6fd1230](https://sqlite.org/src/info/b330c7ff6fd1230?diff=0) + * [746fcd2fd412ddc](https://sqlite.org/src/info/746fcd2fd412ddc?diff=0) + * [71866b367f32b5a](https://sqlite.org/src/info/71866b367f32b5a?diff=0) + * [05418b2a4a6e6a9](https://sqlite.org/src/info/05418b2a4a6e6a9?diff=0) + +Generated by a very similar script: + +~~~~~ +SELECT printf(' * [%s](https://sqlite.org/src/info/%s?diff=0)', hash, hash) FROM ( + SELECT count(*) AS cnt, sum(cherrypick=1) AS cp, sum(cherrypick=0) AS n, + (SELECT substr(uuid,1,15) FROM blob WHERE rid=cid) AS hash + FROM ( + SELECT cid, 0 AS cherrypick FROM plink WHERE NOT isprim + UNION ALL + SELECT childid, 1 FROM cherrypick + ) + GROUP BY cid + HAVING (cp>0 AND n>0) OR cp>2 OR n>2 + ORDER BY cnt +); +~~~~~ diff --git a/test/json.test b/test/json.test new file mode 100644 index 0000000..a55d695 --- /dev/null +++ b/test/json.test @@ -0,0 +1,925 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Test JSON Support +# + +# Make sure we have a build with the json command at all and that it +# is not stubbed out. This assumes the current (as of 2016-01-27) +# practice of eliminating all trace of the fossil json command when +# not configured. If that changes, these conditions might not prevent +# the rest of this file from running. +fossil test-th-eval "hasfeature json" + +if {[normalize_result] ne "1"} { + puts "Fossil was not compiled with JSON support." + test_cleanup_then_return +} + +# We need a JSON parser to effectively test the JSON produced by +# fossil. It looks like the one from tcllib is exactly what we need. +# On ActiveTcl, add it with teacup. On other platforms, YMMV. +# teacup install json +# teacup install json::write +if {[catch {package require json}] != 0} then { + puts { +The "json" package for Tcl is not available. +Please see: https://core.tcl-lang.org/tcllib +} + test_cleanup_then_return +} + +proc json2dict {txt} { + set rc [catch {::json::json2dict $txt} result options] + if {$rc != 0} { + protOut "JSON ERROR: $result" + return {} + } + return $result +} + +# and that the json itself smells ok and has the expected API error code in it +fossil json -expectError +set JR [json2dict $RESULT] +if {$JR eq ""} { + puts "Fossil was not compiled with JSON support (bad JSON)." + test_cleanup_then_return +} +test json-1 {[dict exists $JR resultCode] + && [dict get $JR resultCode] in "FOSSIL-3002 FOSSIL-4102"} + +# Use the CLI interface to execute a JSON command. Sets the global +# RESULT to the response text, and JR to a Tcl dict conversion of the +# response body. +# +# Returns "200" or "500". +proc fossil_json {args} { + global RESULT JR + uplevel 1 fossil json {*}$args + set JR [json2dict $RESULT] + return "200" +} + +# Use the HTTP interface to GET a JSON API URL. Sets the globals +# RESULT to the HTTP response body, and JR to a Tcl dict conversion of +# the response body. +# +# Returns the status code from the HTTP header. +proc fossil_http_json {url {cookie "Muppet=Monster"} args} { + global RESULT JR + set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie" + set RESULT [fossil_maybe_answer $request http {*}$args --ipaddr 127.0.0.1] + set head ""; set body ""; set status "--NO_MATCH--" + regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body + regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg + if {$status eq "200"} { + set JR [json2dict $body] + } + return $status +} + + +# Use the HTTP interface to POST a JSON API URL. Sets the globals +# RESULT to the HTTP response body, and JR to a Tcl dict conversion of +# the response body. +# +# Returns the status code from the HTTP header. +proc fossil_post_json {url data {cookie "Muppet=Monster"} args} { + global RESULT JR + + # set up a full GET or POST HTTP request + set len [string length $data] + if {$len > 0} { + set request [subst {POST $url HTTP/1.0\r +Host: localhost\r +User-Agent: Fossil-Test\r +Cookie: $cookie\r +Content-Type: application/json +Content-Length $len +\r +$data}] + } else { + set request [subst {GET $url HTTP/1.0\r +Host: localhost\r +User-Agent: Fossil-Test\r +Cookie: $cookie\r +\r +}] + } + + # handle the actual request + flush stdout + #exec $fossilexe + set RESULT [fossil_maybe_answer $request http {*}$args --ipaddr 127.0.0.1] + + # separate HTTP headers from body + set head ""; set body ""; set status "--NO_MATCH--" + regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body + regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg + if {$status eq "200"} { + if {[string length $body] > 0} { + set JR [json2dict $body] + } else { + set JR "" + } + } + return $status +} + + +# Inspect a dict for keys it must have and keys it must not have +proc test_dict_keys {testname D okfields badfields} { + if {$D eq ""} { + test $testname-validJSON 0 + return + } + set i 1 + foreach f $okfields { + test "$testname-$i" {[dict exists $D $f]} + incr i + } + foreach f $badfields { + test "$testname-$i" {![dict exists $D $f]} + incr i + } +} + +# Inspect the envelope part of a returned JSON structure to confirm +# that it has specific fields and that it lacks specific fields. +proc test_json_envelope {testname okfields badfields} { + test_dict_keys $testname $::JR $okfields $badfields +} + +# Inspect the envelope of a normal successful result +proc test_json_envelope_ok {testname} { + test_json_envelope $testname [concat fossil timestamp command procTimeUs \ + procTimeMs payload] [concat resultCode resultText] +} + +# Inspect the payload of a successful result to confirm that it has +# specific fields and that it lacks specific fields. +proc test_json_payload {testname okfields badfields} { + test_dict_keys $testname [dict get $::JR payload] $okfields $badfields +} + +#### VERSION AKA HAI + +# The JSON API generally assumes we have a repository, so let it have one. + +# Set FOSSIL_USER to ensure consistent results in "json user list" +set _fossil_user "" +if [info exists env(FOSSIL_USER)] { + set _fossil_user $env(FOSSIL_USER) +} +set ::env(FOSSIL_USER) "JSON-TEST-USER" + +test_setup + +# Stop backoffice from running during this test as it can cause hangs. +fossil settings backoffice-disable 1 + +# Check for basic envelope fields in the result with an error +fossil_json -expectError +test_json_envelope json-enverr [concat resultCode fossil timestamp \ +resultText command procTimeUs procTimeMs] {} +test json-enverr-rc-1 {[dict get $JR resultCode] eq "FOSSIL-3002"} + + +# Check for basic envelope fields in the result with a successful +# command +set HAIfields [concat manifestUuid manifestVersion manifestDate \ +manifestYear releaseVersion releaseVersionNumber \ +resultCodeParanoiaLevel jsonApiVersion] + +fossil_json HAI +test_json_envelope_ok json-HAI +test_json_payload json-HAI $HAIfields {} +test json-HAI-api {[dict get $JR payload jsonApiVersion] >= 20120713} + +# Check for basic envelope fields in a HTTP result with a successful +# command +fossil_http_json /json/HAI +test_json_envelope_ok json-http-HAI +test_json_payload json-http-HAI $HAIfields {} +test json-http-HAI-api {[dict get $JR payload jsonApiVersion] >= 20120713} + +fossil_json version +test_json_envelope_ok json-version +test_json_payload json-version $HAIfields {} +test json-version-api {[dict get $JR payload jsonApiVersion] >= 20120713} + +#### ARTIFACT + +# sha1 of 0 bytes and a file to match in a commit +set UUID_empty da39a3ee5e6b4b0d3255bfef95601890afd80709 +# sha3 of 0 bytes and a file to match in a commit +set UUID_empty_64 a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a +write_file empty "" +fossil add empty +fossil ci -m "empty file" + +# json artifact (checkin) +fossil_json [concat artifact tip] +test_json_envelope_ok json-artifact-checkin-env +test json-artifact-checkin {[dict get $JR payload type] eq "checkin"} +test_json_payload json-artifact \ +[concat type uuid isLeaf timestamp user comment parents tags files] {} + +# json artifact (file) +fossil_json [concat artifact $UUID_empty_64] +test_json_envelope_ok json-artifact-file-env +test json-artifact-file {[dict get $JR payload type] eq "file"} +test_json_payload json-artifact [concat type uuid size checkins] {} + +# json artifact (wiki) +fossil wiki create Empty <<"-=BLANK=-" +fossil_json wiki get Empty +test json-wiki-get {[dict get $JR payload name] eq "Empty"} +set uuid [dict get $JR payload uuid] +fossil_json artifact $uuid +test_json_envelope_ok json-artifact-wiki-env +test json-artifact-wiki {[dict get $JR payload type] eq "wiki"} +test_json_payload json-artifact-wiki [list type uuid artifact] {} +set artifact [dict get $JR payload artifact] +test_dict_keys json-artifact-wiki-artifact $artifact \ + [list name uuid user timestamp size] {} +# name, uuid, parent?, user, timestamp, size?, content? + + +#### AUTHENTICATION +fossil_json anonymousPassword +test_json_envelope_ok json-anonymousPassword-env +test_json_payload json-anonymousPassword {seed password} {} +set seed [dict get $JR payload seed] +set pass [dict get $JR payload password] + +write_file anon-1 [subst { +{ + "command":"login", + "payload":{ + "name":"anonymous", + "anonymousSeed":$seed, + "password":"$pass" + } +} +}] +fossil_json --json-input anon-1 +test_json_envelope_ok json-login-a-env +test_json_payload json-login-a {authToken name capabilities loginCookieName} {} +set AuthAnon [dict get $JR payload] +proc test_hascaps {testname need caps} { + foreach n [split $need {}] { + test $testname-$n {[string first $n $caps] >= 0} + } +} +test_hascaps json-login-c "hz" [dict get $AuthAnon capabilities] + +fossil user new U1 User-1 Uone +fossil user capabilities U1 s +write_file u1 { +{ + "command":"login", + "payload":{ + "name":"U1", + "password":"Uone" + } +} +} +fossil_json --json-input u1 +test_json_envelope_ok json-login-u1-env +test_json_payload json-login-u1 {authToken name capabilities loginCookieName} {} +set AuthU1 [dict get $JR payload] +test_hascaps json-login-c "s" [dict get $AuthU1 capabilities] + +set U1Cookie [dict get $AuthU1 loginCookieName]=[regsub -all {[/]} [dict get $AuthU1 authToken] {%2F} ] +set AnonCookie [dict get $AuthAnon loginCookieName]=[regsub -all {[/]} [dict get $AuthAnon authToken] {%2F} ] + +# json cap +# The CLI user has all rights, and no auth token affects that. This +# is consistent with the rest of the fossil CLI, and with the +# pragmatic argument that using the CLI implies physical access to +# the repo file itself, which can be taunted with many tools +# including raw SQLite which will also ignore authentication. +write_file anon-2 [subst { + {"command":"cap", + "authToken":"[dict get $AuthAnon authToken]" + } +}] +fossil_json --json-input anon-2 +test_json_envelope_ok json-cap-env +test json-cap-CLI {[dict get $JR payload permissionFlags setup]} + +# json cap via POST with authToken in request envelope +set anon2 [read_file anon-2] +fossil_post_json "/json/cap" $anon2 +test json-cap-POSTenv-env-0 {[string length $JR] > 0} +test_json_envelope_ok json-cap-POSTenv-env +if {[catch {test json-cap-POSTenv-name \ + {[dict get $JR payload name] eq "anonymous"} knownBug} jerr]} then { + test json-cap-POSTenv-name-threw 0 + protOut "CAUGHT: $jerr" +} +test json-cap-POSTenv-notsetup {![dict get $JR payload permissionFlags setup]} + + +# json cap via GET with authToken in Cookie header +fossil_post_json "/json/cap" {} $AnonCookie +test json-cap-GETcookie-env-0 {[string length $JR] > 0} +test_json_envelope_ok json-cap-GETcookie-env-0 +if {[catch {test json-cap-GETcookie-name-0 \ + {[dict get $JR payload name] eq "anonymous"}} jerr]} then { + test json-cap-GETcookie-name-0-threw 0 + protOut "CAUGHT: $jerr" +} +test json-cap-GETcookie-notsetup-0 {![dict get $JR payload permissionFlags setup]} + + +# json cap via GET with authToken in a parameter +fossil_post_json "/json/cap?authToken=[dict get $AuthAnon authToken]" {} +test json-cap-GETcookie-env-1 {[string length $JR] > 0} +test_json_envelope_ok json-cap-GETcookie-env-1 +if {[catch {test json-cap-GETcookie-name-1 \ + {[dict get $JR payload name] eq "anonymous"}} jerr]} then { + test json-cap-GETcookie-name-1-threw 0 + protOut "CAUGHT: $jerr" +} +test json-cap-GETcookie-notsetup-1 {![dict get $JR payload permissionFlags setup]} + + +# whoami +# via CLI with no auth token supplied +fossil_json whoami +test_json_envelope_ok json-whoami-cli-env +test_json_payload json-whoami-cli {name capabilities} {} +test json-whoami-cli-name {[dict get $JR payload name] eq "nobody"} +test_hascaps json-whoami-cli-cap "gjorz" [dict get $JR payload capabilities] + +#### BRANCHES +# json branch list +fossil_json branch list +test_json_envelope_ok json-branch-list-env +test_json_payload json-branch-list {range current branches} {} +test json-branch-list-cur {[dict get $JR payload current] eq "trunk"} +test json-branch-list-cnt {[llength [dict get $JR payload branches]] == 1} +test json-branch-list-val {[dict get $JR payload branches] eq "trunk"} + +# json branch create +fossil_json branch create alpha --basis trunk +test_json_envelope_ok json-branch-create-env +test_json_payload json-branch-create {name basis rid uuid isPrivate} {} + + +#### CONFIG +# json config get AREA +# AREAs are skin ticket project all skin-backup +foreach a [list skin ticket project all skin-backup] { + fossil_json config get $a + test_json_envelope_ok json-config-$a-env + # payload depends on specific area and may be completely empty +} + +#### DIFFS +# json diff v1 v2 + +write_file fish { +ABCD goldfish +} +fossil add fish +fossil ci -m "goldfish" +fossil_json finfo fish +set fishHist [dict get $JR payload checkins] +set fishV1 [dict get [lindex $fishHist 0] uuid] + +write_file fish { +ABCD goldfish +LMNO goldfish +} +fossil ci -m "goldfish" +fossil_json finfo fish +set fishHist [dict get $JR payload checkins] +set fishV2 [dict get [lindex $fishHist 0] uuid] + +test fossil-diff-setup {$fishV1 ne $fishV2} +fossil_json diff $fishV1 $fishV2 +test_json_envelope_ok json-diff-env +test_json_payload json-diff {from to diff} {} +test json-diff-v1 {[dict get $JR payload from] eq $fishV1} +test json-diff-v2 {[dict get $JR payload to] eq $fishV2} +set diff [dict get $JR payload diff] +test json-diff-diff {[string first "+LMNO goldfish" $diff] >= 0} +protOut [dict get $JR payload diff] + + +#### DIRECTORY LISTING +# json dir DIRNAME +fossil_json dir +test_json_envelope_ok json-dir-env +test_json_payload json-dir {name entries} {} + +#### FILE INFO +# json finfo FILENAME +fossil_json finfo empty +test_json_envelope_ok json-finfo-env +test_json_payload json-finfo {name checkins} {} + +#### QUERY +# json query SQLCODE +fossil_json query {"SELECT * FROM reportfmt"} +test_json_envelope_ok json-query-env +test_json_payload json-query {columns rows} {} + +#### STATS +# json stat +fossil_json stat +test_json_envelope_ok json-stat-env +test_json_payload json-stat {repositorySize ageDays ageYears projectCode compiler sqlite} \ +{blobCount deltaCount uncompressedArtifactSize averageArtifactSize maxArtifactSize \ +compressionRatio checkinCount fileCount wikiPageCount ticketCount} + +fossil_json stat -f +test_json_envelope_ok json-stat-env +test_json_payload json-stat {repositorySize \ +blobCount deltaCount uncompressedArtifactSize averageArtifactSize maxArtifactSize \ +compressionRatio checkinCount fileCount wikiPageCount ticketCount \ +ageDays ageYears projectCode compiler sqlite} {} + + +#### STATUS +# NOTE: Local checkout required +# json status +fossil_json status +test_json_envelope_ok json-status-env +test_json_payload json-status {repository localRoot checkout files errorCount} {} + +#### TAGS + +# json tag add NAME CHECKIN VALUE +fossil_json tag add blue trunk green +test_json_envelope_ok json-tag-add-env +test_json_payload json-tag-add {name value propagate raw appliedTo} {} + + +# json tag cancel NAME CHECKIN +fossil_json tag add cancel alpha +test_json_envelope_ok json-tag-cancel-env +# DOCBUG? Doc says no payload. +test_json_payload json-tag-cancel {name value propagate raw appliedTo} {} + +# json tag find NAME +fossil_json tag find alpha +test_json_envelope_ok json-tag-find-env +test_json_payload json-tag-find {name raw type limit artifacts} {} +test json-tag-find-count {[llength [dict get $JR payload artifacts]] >= 1} + +# json tag list CHECKIN +fossil_json tag list +test_json_envelope_ok json-tag-list-env +test_json_payload json-tag-list {raw includeTickets tags} {} +test json-tag-list-count {[llength [dict get $JR payload tags]] >= 2} + + +#### TICKETS +# API Docs say not yet defined, so it isn't quite fair to mark this +# category as TODO for the test cases... + +#### TICKET REPORTS + +# json report get NUMBER +fossil_json report get 1 +test_json_envelope_ok json-report-get-env +test_json_payload json-report-get {report owner title timestamp columns sqlCode} {} + +# json report list +fossil_json report list +test_json_envelope_ok json-report-list-env +#test_json_payload json-report-list {raw includeTickets tags} {} +test json-report-list-count {[llength [dict get $JR payload]] >= 1} + + +# json report run NUMBER +fossil_json report run 1 +test_json_envelope_ok json-report-run-1-env +test_json_payload json-report-list {report title sqlcode columnNames tickets} {} +test json-report-list-count {[llength [dict get $JR payload columnNames]] >= 7} +test json-report-list-count {[llength [dict get $JR payload tickets]] >= 0} + + +#### TIMELINE + +# json timeline checkin +fossil_json timeline checkin +test_json_envelope_ok json-timeline-checkin-env +test_json_payload json-timeline-checkin {limit timeline} {} +set i 0 +foreach t [dict get $JR payload timeline] { + # parents appears only for entries that have a parent + # files appears only if requested by the --files parameter + test_dict_keys json-timeline-checkin-$i $t {type uuid timestamp comment user isLeaf tags} {} + incr i +} + +# json timeline ci +# removed from documentation +#fossil_json timeline ci +#test json-timeline-ci {[dict get $JR resultCode] ne "FOSSIL-1102"} knownBug +#test_json_payload json-timeline-ci {limit timeline} {} + +# json timeline ticket +fossil_json timeline ticket +test_json_envelope_ok json-timeline-ticket-env +test_json_payload json-timeline-ticket {limit timeline} {} + +# json timeline wiki +fossil_json timeline wiki +test_json_envelope_ok json-timeline-wiki-env +test_json_payload json-timeline-wiki {limit timeline} {} + + +#### USER MANAGEMENT + +# json user get +foreach u [list nobody anonymous reader developer U1] { + fossil_json user get $u + test_json_envelope_ok json-user-get-$u-env + test_json_payload json-user-get-$u {uid name capabilities info timestamp} {} +} + +# json user list +fossil_json user list +test_json_envelope_ok json-user-list-env +set i 0 +foreach u [dict get $JR payload] { + test_dict_keys json-user-list-$i $u {uid name capabilities info timestamp} {} + incr i +} + +# json user save +fossil_json user save --uid -1 --name U2 --password Utwo +test_json_envelope_ok json-user-save-env +test_json_payload json-user-save {uid name capabilities info timestamp} {} + + +# DOCBUG? Doc says payload is "same as /json/user/get" but actual +# result was an array of one user similar to /json/user/list. +#set i 0 +#foreach u [dict get $JR payload] { +# test_dict_keys json-user-save-$i $u {uid name capabilities info timestamp} {} +# incr i +#} +#test json-user-save-count {$i == 1} + + + +#### WIKI + +# wiki list +fossil_json wiki list +test_json_envelope_ok json-wiki-list-env +set pages [dict get $JR payload] +test json-wiki-1 {[llength $pages] == 1} +test json-wiki-2 {[lindex $pages 0] eq "Empty"} +fossil_json wiki list --verbose +set pages [dict get $JR payload] +test json-wiki-verbose-1 {[llength $pages] == 1} +test_dict_keys json-wiki-verbose-pages [lindex $pages 0] [list name uuid user timestamp size] {} + +# wiki get +fossil_json wiki get Empty +test_json_envelope_ok json-wiki-get-env +# this page has only one version, so no parent should be listed +test_json_payload json-wiki-get [list name uuid user timestamp size content] [list parent] + + +# wiki create +# requires an authToken? Not from CLI. + +write_file req.json { + { + "command":"wiki/create", + "payload":{ + "name":"Page2", + "content":"Lorem ipsum dolor sic amet." + } + } +} +fossil_json --json-input req.json +test_json_envelope_ok json-wiki-create-env +fossil_json wiki get Page2 +test_json_envelope_ok json-wiki-create-get-env +test_json_payload json-wiki-save-get [list name uuid user timestamp size content] {parent} +set uuid1 [dict get $JR payload uuid] + +# wiki save + +write_file req2.json { + { + "command":"wiki/save", + "payload":{ + "name":"Page2", + "content":"Lorem ipsum dolor sic amet.\nconsectetur adipisicing elit." + } + } +} +fossil_json --json-input req2.json +test_json_envelope_ok json-wiki-save-env +fossil_json wiki get Page2 +test_json_envelope_ok json-wiki-save-get-env +test_json_payload json-wiki-save-get [list name uuid user timestamp size parent content] {} +set uuid2 [dict get $JR payload uuid] +test json-wiki-save-parent {[dict get $JR payload parent] eq $uuid1} + +# wiki diff + +fossil_json wiki diff $uuid1 $uuid2 +test_json_envelope_ok json-wiki-diff-env +test_json_payload json-wiki-diff [list v1 v2 diff] {} +test json-wiki-diff-v1 {[dict get $JR payload v1] eq $uuid1} +test json-wiki-diff-v1 {[dict get $JR payload v2] eq $uuid2} +set diff [dict get $JR payload diff] +test json-wiki-diff-diff {[string first "+consectetur adipisicing elit" $diff] >= 0} +#puts [dict get $JR payload diff] + +# wiki preview +# +# takes a string in fossil wiki markup and return an HTML fragment. +# This command does not make use of the actual wiki content (much?) +# at all. +write_file req3.json { + { + "command":"wiki/preview", + "payload":"Lorem ipsum dolor sic amet.\nconsectetur adipisicing elit." + } +} +fossil_json --json-input req3.json +test_json_envelope_ok json-wiki-preview-env +set pv [dict get $JR payload] +test json-wiki-preview-out-1 {[string first "

Lorem ipsum" $pv] == 0} +test json-wiki-preview-out-2 {[string last "

" $pv] == 0} + +#### UNAVOIDABLE MISC + +# json g +fossil_json g +test_json_envelope_ok json-g-env +#puts [llength [dict keys [dict get $JR payload]]] +test json-g-g {[llength [dict keys [dict get $JR payload]]] >= 60};# 64 on my PC + +# json rebuild +fossil_json rebuild +test_json_envelope json-rebuild-env [concat fossil timestamp command procTimeUs \ + procTimeMs] [concat payload resultCode resultText] + +# json resultCodes +fossil_json resultCodes +test_json_envelope_ok json-resultCodes-env +set codes [dict get $JR payload] +test json-resultCodes-codes-1 {[llength $codes] >= 35} ;# count as of API 20120713 +# foreach c $codes { +# puts [dict values $c] +# } +foreach r $codes { + protOut "# [dict get $r resultCode] [dict get $r cSymbol]\n# [dict get $r description]" +} + + + +#### From the API Docs + +# Reminder to self: in March 2012 i saw a corner-case which returns +# HTML output. To reproduce: chmod 444 REPO, then submit a request +# which writes something (timeline creates a temp table). The "repo +# is not writable" error comes back as HTML. i don't know if the +# error happens before we have made the determination that the app is +# in JSON mode or if the error handling is incorrectly not +# recognizing JSON mode. +# +#test_setup x.fossil +fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Dwal $U1Cookie +test json-ROrepo-1-1 {$CODE == 0} +test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]} +test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} +test_json_envelope_ok json-http-timeline1 +if {$is_windows} then { + catch {exec attrib +r .rep.fossil}; # Windows +} else { + catch {exec chmod 444 .rep.fossil}; # Unix +} +protOut "chmod 444 repo" +fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Ddelete $U1Cookie -expectError --json-preserve-rc +test json-ROrepo-2-1 {$CODE != 0} +test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} +test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} +#test_json_envelope_ok json-http-timeline2 +if {$is_windows} then { + catch {exec attrib -r .rep.fossil}; # Windows + catch {exec attrib -r .rep.fossil-shm} + catch {exec attrib -r .rep.fossil-wal} +} else { + catch {exec chmod 666 .rep.fossil}; # Unix + catch {exec chmod 666 .rep.fossil-shm} + catch {exec chmod 666 .rep.fossil-wal} +} +protOut "chmod 666 repo" + +#### Result Codes +# Test cases designed to stimulate each (documented) error code. + +# FOSSIL-0000 +# Not returned by any command. We generally verify that in the +# test_json_envelope_ok command by verifying that the resultCode +# field is not present. Should any JSON endpoint begin to use the +# range reserved for non-fatal warnings, those tests will fail. +# +# Notice that code is not included in the list returned from +# /json/resultCodes. + + +# FOSSIL-1000 FSL_JSON_E_GENERIC +# Generic error + +# FOSSIL-1101 FSL_JSON_E_INVALID_REQUEST +# Invalid request +write_file e1101.json { + ["command","nope"] +} +fossil_json --json-input e1101.json -expectError +test json-RC-1101-array-CLI-exit {$CODE != 0} +test_json_envelope json-RC-1101-array-env {fossil timestamp command procTimeUs \ +procTimeMs resultCode resultText} {payload} +test json-RC-1101-array-code {[dict get $JR resultCode] eq "FOSSIL-1101"} + +write_file e1101.json { + "Not really a command but more of a suggestion" +} +fossil_json --json-input e1101.json -expectError +test json-RC-1101-string-CLI-exit {$CODE != 0} +test_json_envelope json-RC-1101-string-env {fossil timestamp command procTimeUs \ +procTimeMs resultCode resultText} {payload} +test json-RC-1101-string-code {[dict get $JR resultCode] eq "FOSSIL-1101"} + + + + +# FOSSIL-1102 FSL_JSON_E_UNKNOWN_COMMAND +# Unknown command or subcommand +fossil_json NoSuchEndpoint -expectError +test json-RC-1102-CLI-exit {$CODE != 0} +test_json_envelope json-RC-1102-env {fossil timestamp command procTimeUs \ +procTimeMs resultCode resultText} {payload} +test json-RC-1102-code {[dict get $JR resultCode] eq "FOSSIL-1102"} + +write_file e1102.json { + { + "command":"no/such/endpoint" + } +} +fossil_json --json-input e1102.json -expectError +test json-env-RC-1102a-CLI-exit {$CODE != 0} +test_json_envelope json-env-RC-1102a-env {fossil timestamp command procTimeUs \ +procTimeMs resultCode resultText} {payload} +test json-env-RC-1102a-code {[dict get $JR resultCode] eq "FOSSIL-1102"} + + +# FOSSIL-1103 FSL_JSON_E_UNKNOWN +# Unknown error + +write_file bad.sql { +CREATE TABLE spam(a integer, b text); +} +exec $::fossilexe sqlite3 --no-repository bad.fossil + + + +

+ Fossil link test app. Select links from the list below to load + them. Use the arrow keys to cycle through the list. The links are + loaded within an iframe, so navigation within it will stay within + that frame. +
+
+ +
+ + +
+ +
+ + + diff --git a/test/link-tester.js b/test/link-tester.js new file mode 100644 index 0000000..b7d4b10 --- /dev/null +++ b/test/link-tester.js @@ -0,0 +1,224 @@ +/** + JS code for link-tester.html. We cannot host this JS inline in that + file because fossil's default Content Security Policy won't let it + run that way. +*/ +window.addEventListener("DOMContentLoaded", function(){ + const E = function(s){ + const e = document.querySelector(s); + if( !e ) throw new Error("Missing element: "+s); + return e; + }; + const EAll = function(s){ + const e = document.querySelectorAll(s); + if( !e || !e.length ) throw new Error("Missing elements: "+s); + return e; + }; + const eIframe = E('#iframe'); + const eSelect = E('#selectPage'); + const eCurrentUrl = E('#currentUrl'); + + /* + Prepend the fossil instance's URL to each link. We have to guess + which part of the URL is the fossil CGI/server instance. The + following works when run (A) from under /uv or /ext and (B) from + /doc/branchname/test/link-tester.html. + */ + let urlTop; + let loc = (''+window.location); + let aLoc = loc.split('/') + aLoc.pop(); /* file name */ + const thisDir = aLoc.join('/'); + const rxDoc = /.*\/doc\/[^/]+\/.*/; + //console.log(rxDoc, loc, aLoc); + if( loc.match(rxDoc) ){ + /* We're hopefully now at the top-most fossil-served + URL. */ + aLoc.pop(); aLoc.pop(); /* /doc/foo */ + aLoc.pop(); /* current dir name */ + }else{ + aLoc.pop(); /* current dir name */ + } + urlTop = aLoc.join('/'); + //console.log(urlTop, aLoc); + for( const o of eSelect.options ){ + o.value = urlTop + (o.value || o.innerText); + } + + const updateUrl = function(opt){ + if( opt ){ + let url = (opt.value || opt.innerText); + eCurrentUrl.innerText = url.replace(urlTop,''); + eCurrentUrl.setAttribute('href', url); + }else{ + eCurrentUrl.innerText = ''; + } + }; + + eSelect.addEventListener('change',function(ev){ + const so = ev.target.options[ev.target.selectedIndex]; + if( so ){ + eIframe.setAttribute('src', so.value || so.innerText); + updateUrl(so); + } + }); + + /** Select the entry at the given ndx and fire a change event. */ + const selectEntry = function(ndx){ + if( ndx>=0 ){ + eSelect.selectedIndex = ndx; + eSelect.dispatchEvent(new Event('change',{target:eSelect})); + } + }; + + /* Cycle to the next link in the list, accounting for separators and + wrapping around at either end. */ + const cycleLink = function(dir/*<0 = prev, >0 = next*/){ + let n = eSelect.selectedIndex + dir; + if( n < 0 ) n = eSelect.options.length-1; + else if( n>=eSelect.options.length ){ + n = 0; + } + const opt = eSelect.options[n]; + if( opt && opt.disabled ){ + /* If that OPTION element is disabled, skip over it. */ + eSelect.selectedIndex = n; + cycleLink(dir); + }else{ + selectEntry(n); + } + }; + + E('#btn-prev').addEventListener('click', ()=>cycleLink(-1), false); + E('#btn-next').addEventListener('click', ()=>cycleLink(1), false); + + /** + We have to adjust the iframe's size dynamically to account for + other widgets around it. iframes don't simply like to fill up all + available space without some help. If #controlWrapper only + contained the one SELECT element, CSS would be sufficient, but + once we add text around it, #controlWrapper's size becomes + unpredictable and we need JS to calculate it. We do this every + time the window size changes. + */ + const effectiveHeight = function f(e){ + // Copied from fossil.dom.js + if(!e) return 0; + if(!f.measure){ + f.measure = function callee(e, depth){ + if(!e) return; + const m = e.getBoundingClientRect(); + if(0===depth){ + callee.top = m.top; + callee.bottom = m.bottom; + }else{ + callee.top = m.top ? Math.min(callee.top, m.top) : callee.top; + callee.bottom = Math.max(callee.bottom, m.bottom); + } + Array.prototype.forEach.call(e.children,(e)=>callee(e,depth+1)); + if(0===depth){ + //console.debug("measure() height:",e.className, callee.top, callee.bottom, (callee.bottom - callee.top)); + f.extra += callee.bottom - callee.top; + } + return f.extra; + }; + } + f.extra = 0; + f.measure(e,0); + return f.extra; + }; + + /* Helper for the window-resized event handler below, to avoid + handling the resize until after it's finished. */ + const debounce = function f(func, waitMs, immediate) { + // Copied from fossil.bootstrap.js + var timeoutId; + if(!waitMs) waitMs = f.$defaultDelay; + return function() { + const context = this, args = Array.prototype.slice.call(arguments); + const later = function() { + timeoutId = undefined; + if(!immediate) func.apply(context, args); + }; + const callNow = immediate && !timeoutId; + clearTimeout(timeoutId); + timeoutId = setTimeout(later, waitMs); + if(callNow) func.apply(context, args); + }; + }; + + /** + Resize eConstrained (the ifame element) so that it fits within + the page space not occupied by the list of elements eToAvoid. + */ + const ForceResizeKludge = (function(eToAvoid, eConstrained){ + const resized = function f(){ + if( f.$disabled ) return; + const wh = window.innerHeight; + let ht; + let extra = 0; + eToAvoid.forEach((e)=>e ? extra += effectiveHeight(e) : false); + ht = wh - extra; + if( ht < 100 ) ht = 100; + eConstrained.style.top = 'calc('+extra+'px + 2em)'; + eConstrained.style.height = + eConstrained.style.maxHeight = "calc("+ ht+ "px - 2em)"; + }; + resized.$disabled = true/* gets deleted later */; + window.addEventListener('resize', debounce(resized, 250), false); + return resized; + })( + EAll('body > *:not(iframe)'), + eIframe + ); + + delete ForceResizeKludge.$disabled; + ForceResizeKludge(); + + selectEntry(0); + + /** + Read link-tester.json, which should live in the same directory + as this file. It's expected to be an array with entries + in one of the following forms: + + - "string" = Separator label (disabled) + - ["/path"] = path with itself as a label + - ["label", "/path"] = path with the given label + + All paths are expected to have a "/" prefix and this script + accounts for mapping that to the fossil part of this script's + URL. + */ + window.fetch(thisDir+'/link-tester.json').then((r)=>r.json()).then(j=>{ + //console.log("fetched",j); + eSelect.innerHTML = ''; + const opt = function(arg){ + const o = document.createElement('option'); + //console.warn(arguments); + let rc = true; + if( 'string' === typeof arg ){ + /* Grouping separator */ + o.innerText = "--- " + arg + " ---"; + o.setAttribute('disabled',''); + rc = false; + }else if( 1===arg.length ){ + o.innerText = arg[0]; + o.value = urlTop + arg[0]; + }else if( 2==arg.length ){ + o.innerText = arg[0]; + o.value = urlTop + arg[1]; + } + eSelect.appendChild(o); + return rc; + }; + let ndx = -1/*index of first non-disabled entry*/, i = 0; + for(const e of j){ + if( opt(e) && ndx<0 ){ + ndx = i; + } + ++i; + } + selectEntry(ndx); + }); +}); diff --git a/test/link-tester.json b/test/link-tester.json new file mode 100644 index 0000000..5611bbc --- /dev/null +++ b/test/link-tester.json @@ -0,0 +1,68 @@ +[ + "Timelines", + ["Default", "/timeline"], + ["anonymous", "/timeline?u=anonymous&y=a"], + ["after date/time", "/timeline?n=12&y=ci&a=2024-12-31T20:29Z"], + ["after hash", "/timeline?n=12&y=ci&a=3cb092c0e2f0ff26"], + ["before date/time", "/timeline?n=12&y=ci&b=2024-12-31T20:30Z"], + ["before hash", "/timeline?n=12&y=ci&b=3cb092c0e2f0ff26"], + ["circa date/time", "/timeline?n=12&y=ci&c=2024-12-31T20:29Z"], + ["circa hash", "/timeline?n=12&y=ci&c=3cb092c0e2f0ff26"], + ["d=,p=", "/timeline?d=version-2.25&p=version-2.26"], + ["from=,ft=", "/timeline?from=2765f04694d36e68&ft=release"], + ["from=,ft=,min", "/timeline?from=2765f04694d36e68&ft=release&min"], + ["from=,to=", "/timeline?from=version-2.25&to=version-2.26"], + ["from=,to=,min", "/timeline?from=version-2.25&to=version-2.26&min"], + ["omit-cr branch", "/timeline?r=omit-cr&m&c=7e97f4999b16ab75"], + ["diff-eolws branch", "/timeline?r=diff-eolws&n=50"], + ["Shortest path (from=,to=)", + "/timeline?from=e663bac6f7&to=a298a0e2f9&shortest"], + ["Common Ancestor (me=,you=)", + "/timeline?me=e663bac6f7&you=a298a0e2f9"], + + "Diff", + ["Multiple edits on a single line", "/info/030035345c#chunk73"], + ["Tricky alignment, multiple edits per line", + "/fdiff?v1=6da016415dc52d61&v2=af6df3466e3c4a88"], + ["Column alignment with multibyte characters", + "/fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113"], + ["Large diff of sqlite3.c - was once very slow", + "/fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"], + ["A difficult indentation change", "/info/bda00cbada#chunk49"], + ["Inverse of the previous", + "/fdiff?v1=bc8100c9ee01b8c2&v2=1d2acc1a2a65c2bf#chunk42"], + ["Another tricky indentation", + "/fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"], + ["Inverse of the previous", + "/fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"], + ["A tricky alignment", + "/fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk24"], + ["sqlite3.c changes that are difficult to align", + "/fdiff?v1=21f9a00fe2fa4a17&v2=d5c4ff0532bd89c3#chunk5"], + ["Lorem Ipsum in Greek", "/fdiff?v1=4f70c682e44f&v2=55659c6e062994f"], + ["Inverted Greek Lorem Ipsum", "/fdiff?v2=4f70c682e44f&v1=55659c6e062994f"], + + "Infos", + ["Merge riser coalescing #1", "/info/eed3946bd92a499?diff=0"], + ["Merge riser coalescing #2", "/info/ef6979eac9abded?diff=0"], + ["Merge riser coalescing #3", "/info/9e1fa626e47f147?diff=0"], + ["Merge riser coalescing #4", "/info/68bd2e7bedb8d05?diff=0"], + ["Merge riser coalescing #5", "/info/7766e689926c703?diff=0"], + ["Merge riser coalescing #6", "/info/3ea66260b5555d2?diff=0"], + ["Merge riser coalescing #7", "/info/66ae70a54b20656?diff=0"], + ["Context graph #1", "/info/b0f2a0ac53926c9?diff=0"], + ["Context graph #2", "/info/303e7af7c31866c?diff=0"], + ["Context graph #3", "/info/b31afcc2cab1dc4?diff=0"], + ["Context graph #4", "/info/1a164e5fb76a46b?diff=0"], + ["Context graph #5", "/info/2d75e87b760c0a9?diff=0"], + ["Context graph #6", "/info/76442af7e13267bd?diff=0"], + ["Info about the tip", "/info/tip"], + ["/info/tip"], + + "Admin", + ["Users", "/setup_ulist"], + + "Misc.", + ["/skins"], + ["/chat"] +] diff --git a/test/many-www.tcl b/test/many-www.tcl new file mode 100644 index 0000000..414b1c7 --- /dev/null +++ b/test/many-www.tcl @@ -0,0 +1,81 @@ +#!/usr/bin/tclsh +# +# Run this script from within any open Fossil checkout. Example: +# +# tclsh many-www.tcl | tee out.txt +# +# About 10,000 different web page requests will be made. Each is timed +# and the time shown on output. Use this script to search for segfault problems +# or to look for pages that need optimization. +# +proc run_query {url} { + set fd [open q.txt w] + puts $fd "GET $url HTTP/1.0\r\n\r" + close $fd + return [exec fossil test-http 1000000} { + set x [string range $x 0 1000000] + } + set k 0 + while {[regexp {<[aA] .*?href="(/[a-z].*?)".*?>(.*)$} $x all url tail]} { + # if {$npending>2*($limit - $i)} break + incr k + if {$k>100} break + set u2 [string map {< < > > " \" & &} $url] + if {![info exists seen($u2)]} { + set next($u2) 1 + set seen($u2) 1 + } + set x $tail + } +} diff --git a/test/markdown-test1.md b/test/markdown-test1.md new file mode 100644 index 0000000..891cfde --- /dev/null +++ b/test/markdown-test1.md @@ -0,0 +1,25 @@ + +Markdown Formatter Test Document +================================ + +This document is designed to test the markdown formatter. + + * A bullet item. + * A subitem + * Second bullet + +More text + + 1. Enumeration + 1.1. Subitem 1 + 1.2. Subitem 2 + 2. Second enumeration. + +Another paragraph. + + + +Other Features +-------------- + +Text can show *emphasis* or _emphasis_ or **strong emphassis**. diff --git a/test/markdown-test2.md b/test/markdown-test2.md new file mode 100644 index 0000000..cf41ef4 --- /dev/null +++ b/test/markdown-test2.md @@ -0,0 +1,79 @@ +# Markdown Emphasis Test Cases + + + +See + +| Id | Source Text | Actual Rendering | Correct Rendering | +----------------------------------------------------------------------------- +| 1:| `*foo bar*` | *foo bar* | foo bar | +| 2:| `a * foo bar*` | a * foo bar* | a * foo bar* | +| 3:| `a*"foo"*` | a*"foo"* | a*"foo"* | +| 4:| `* a *` | * a * | * a * | +| 5:| `foo*bar*` | foo*bar* | foobar | +| 6:| `5*6*78` | 5*6*78 | 5678 | +| 7:| `_foo bar_` | _foo bar_ | foo bar | +| 8:| `_ foo bar_` | _ foo bar_ | _ foo bar_ | +| 9:| `a_"foo"_` | a_"foo"_ | a_"foo"_ | +| 10:| `foo_bar_` | foo_bar_ | foo_bar_ | +| 11:| `5_6_78` | 5_6_78 | 5_6_78 | +| 12:| `aa_"bb"_cc` | aa_"bb"_cc | aa_"bb"_cc | +| 13:| `foo-_(bar)_` | foo-_(bar)_ | foo-(bar) | +| 14:| `*(*foo` | *(*foo | *(*foo | +| 15:| `*(*foo*)*` | *(*foo*)* | (foo) | +| 16:| `*foo*bar` | *foo*bar | foobar | +| 17:| `_foo bar _` | _foo bar _ | _foo bar _ | +| 18:| `_(_foo)` | _(_foo) | _(_foo) | +| 19:| `_(_foo_)_` | _(_foo_)_ | (foo) | +| 20:| `_foo_bar` | _foo_bar | _foo_bar | +| 21:| `_foo_bar_baz_` | _foo_bar_baz_ | foo_bar_baz | +| 22:| `foo_bar_baz` | foo_bar_baz | foo_bar_baz | +| 23:| `_(bar)_` | _(bar)_ | (bar) | + + +# Strong emphasis + + +| Id | Source Text | Actual Rendering | Correct Rendering | +------------------------------------------------------------------------------------------- +| 1:| `**foo bar**` | **foo bar** | foo bar | +| 2:| `a ** foo bar**` | a ** foo bar** | a ** foo bar** | +| 3:| `a**"foo"**` | a**"foo"** | a**"foo"** | +| 4:| `** a **` | ** a ** | ** a ** | +| 5:| `foo**bar**` | foo**bar** | foobar | +| 6:| `5**6**78` | 5**6**78 | 5678 | +| 7:| `__foo bar__` | __foo bar__ | foo bar | +| 8:| `__ foo bar__` | __ foo bar__ | __ foo bar__ | +| 9:| `a__"foo"__` | a__"foo"__ | a__"foo"__ | +| 10:| `foo__bar__` | foo__bar__ | foo__bar__ | +| 11:| `5__6__78` | 5__6__78 | 5__6__78 | +| 12:| `aa__"bb"__cc` | aa__"bb"__cc | aa__"bb"__cc | +| 13:| `foo-__(bar)__` | foo-__(bar)__ | foo-(bar) | +| 14:| `**(**foo` | **(**foo | **(**foo | +| 15:| `**(**foo**)**` | **(**foo**)** | (foo) | +| 16:| `**foo**bar` | **foo**bar | foobar | +| 17:| `__foo bar __` | __foo bar __ | __foo bar __ | +| 18:| `__(__foo)` | __(__foo) | __(__foo) | +| 19:| `__(__foo__)__` | __(__foo__)__ | (foo) | +| 20:| `__foo__bar` | __foo__bar | __foo__bar | +| 21:| `__foo__bar__baz__` | __foo__bar__baz__ | foo__bar__baz | +| 22:| `foo__bar__baz` | foo__bar__baz | foo__bar__baz | +| 23:| `__(bar)__` | __(bar)__ | (bar) | diff --git a/test/markdown-test3.md b/test/markdown-test3.md new file mode 100644 index 0000000..a9f69ac --- /dev/null +++ b/test/markdown-test3.md @@ -0,0 +1,256 @@ + +Markdown Footnotes Test Document +================================ + +**This document** should help with testing of footnotes support that +is introduced by the ["`markdown-footnotes`"][branch] branch. +It **might look pretty misformatted unless rendered by the proper Fossil +executable** that incorporates the abovementioned branch.[^1] +That is also a humble attempt to explore the robustness of the Markdown parser. +So please excuse for the mess in the [source code of this document][src]. +By no means the normal use of footnotes should look that scarry. + +Developers are invited to add test cases here[^here]. +It is suggested that the more simple is a test case the earlier it should +appear in this document.[^ if glitch occurs ] + + +[^lost3]: This note was defined at the begining of the document. + +[^duplicate]: This came from the begining of the document. + +A footnote's label should be case insensitive[^ case INSENSITIVE ], +it is whitespace-savvy and can even contain newlines.[^ a +multiline +label] + +A labeled footnote may be [referenced several times][^many-refs]. + +A footnote's text should support Markdown [markup][^]. +Markup within [a [text fragment](https://en.wikipedia.org/wiki/Lorem_ipsum) +of a *span-bounded footnote*][^markup] should also be rendered. + +Another reference[^many-refs] to the preveously used footnote. + +[^lost2]: This note was defined in the middle of the document. + It references [its previous][^lost3] + and [the forthcoming][^lost1] siblings. + +[^i am strayed]: + This should be presented **verbatim** (without any [markup][^]) + in the end of the footnotes. + + Default skin renders label in red font and the main text in gray. + Other styling may also apply. + +Inline footnotes are supported.(^These may be usefull for adding +small comments.) + +This is a corner case that is rendered as [an empty footnote](^ [] ()). + +If [undefined label is used][^] then red "`misref`" is emited instead of +a numeric marker.[^ see it yourself ] +This can be overridden by the skin though. + +The refenrence at the end of this sentence is the sole reason of +rendering of `lost1` and [lost2][^]. + +If several labeled footnote definitions have the same equal label then texts +from all these definitions are joined.[^duplicate] + +Several references should be recognized as several distinct numbers. +(^There should be an interval between numbers.) [^many-refs] + +If markup is ambigous between a span-bounded footnote and +a "free-standing" footnote followed by another footnote +then interpret as the later case. +This facilitates the usage in the usual case +when several footnotes are refenrenced at the end +of a phrase.[^scipub][^many-refs](^All these four should +be parsed as "free-standing" footnotes)[^Coelurosauria] + +An ambiguity between a link to an image and a *free-standing referenced +footnote* should be resolved as a footnote![^not-image] + +A footnote may not be empty(^) +or consist just of blank characters.(^ + ) + +The same holds for labeled footnotes. If definition of a labeled footnote +is blank then it is not accepted by the first pass of the parser and +is recognized during the second pass as misreference. +[^ This definition consists of just blanks ]: + + + + +It is possible to provide a list of classes for a particular footnote and +all its references. This is achieved by prepending a footnote's text with +a special token that starts with dot and ends with colon. +(^ + .alpha-Numeric123.EXAMPLE: + This token defines a dot-separated list of CSS classes + which are added to that particular footnote and also to the + corresponding reference(s). Hypens ('-') are also allowed. + Classes from the token are tranformed to lowercase and are prepended + with `"fn-upc-"` to avoid collisions. +) +This feature is "*opt-in*": there is nothing wrong in starting a footnote's +text with a token of that form while not defining any corresponding classes +in the stylesheet.[^nostyle] +If a footnote consists just of a valid userclass token then this token +is not interpreted as such, instead it is emitted as plain text. +(^ + .bare.classlist.inside.inline.footnote: +)[^bare1] +[^bare2] + +[^duplicate]: .with.UPC.token: + When duplicates are joined their UPC tokens are treated as plain-text. + Blank characters between token and main text must be preserved. + + + Click + + here and + + here + to test escaping of REQUEST_URI in the generated footnote markers. + + +A depth of nesting must be limited. +(^ + .L.1: A long chain of nested inline footnotes... + (^ + .L.2: is a rather unusual thing... + (^ + .L.3: and requires extra CPU cycles for processing. + (^ + .L.4: Theoretically speaking O(n2). + (^ + .L.5: Thus it is worth dismissing those footnotes... + (^ + .L.6: that are nested deeper than on a certain level. + (^ + .L.7: A particular value for that limit... + (^ + is hard-coded in src/markdown.c ... + (^ + in function `markdown()` ... + (^ + in variable named `maxDepth`. + (^ + For the time being, its value is **5** + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) +) + +## Footnotes + +[branch]: /timeline?r=markdown-footnotes&nowiki + +[^ 1]: Footnotes is a Fossil extension of + Markdown. Your other tools may have limited support for these. + +[^here]: [History of test/markdown-test3.md](/finfo/test/markdown-test3.md) + +[src]: /file/test/markdown-test3.md?ci=markdown-footnotes&txt&ln + +[^if glitch occurs]: + So that simple cases are processed even if + a glitch happens for more tricky cases. + +[^ CASE insensitive ]: And also tolerate whitespaces. + +[^ a multiline label ]: But at a footnote's definition it should still + be written within square brackets + on a single line. + +[^duplicate]: And that came from the end of the document. + +[^many-refs]: + Each letter on the left is a back-reference to the place of use. + Highlighted back-reference indicates a place from which navigation + occurred[^lost1]. + +[^lost1]: This note was defined at the end of the document. + It defines an inline note. + + (^This is inline note defined inside of [a labeled note][^lost1].) + +[^markup]: E.g. *emphasis*, and [so on](/md_rules). + BTW, this note may not have a backreference to the "stray". + +[^undefined label is used]: For example due to a typo. + +[^not-image]: The rationale is that URLs do not start with **^** + while a footnote may follow *immediately* after an exclamation mark + at the end of a sentence. + +[^another stray]: Just to verify the correctness of ordering and styling. + +[^scipub]: Which is common in the scientific publications. + +[^bare1]: .at.the.1st.line.of.labeled.footnote.definition: + + +[^bare2]: + .at.the.2nd.line.of.labeled.footnote.definition: + +[^stray with UPC]: .UPC-token: + A token of user-provided classes must be rendered within strays. + Aslo: this and the previous line may not have extra indentation. + +[^nostyle]: + .unused.classes: + In that case text of the footnote just looks like as if + no special processing occured. + + +[^ ]: Labels are escaped + +[^ diff --git a/test/merge1.test b/test/merge1.test new file mode 100644 index 0000000..a3992c9 --- /dev/null +++ b/test/merge1.test @@ -0,0 +1,433 @@ +# +# Copyright (c) 2006 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the 3-way merge +# + +test_setup "" + +write_file_indented t1 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t2 { + 111 - This is line ONE of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t3 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test OF THE merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t23 { + 111 - This is line ONE of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test OF THE merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +fossil 3-way-merge t1 t3 t2 a32 +test merge1-1.1 {[same_file t23 a32]} +fossil 3-way-merge t1 t2 t3 a23 +test merge1-1.2 {[same_file t23 a23]} + +write_file_indented t1 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t2 { + 111 - This is line ONE of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t3 { + 111 - This is line one OF the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t23 { + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) + 111 - This is line ONE of the demo program - 1111 + ####### SUGGESTED CONFLICT RESOLUTION follows ################### + 111 - This is line ONE OF the demo program - 1111 + ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + 111 - This is line one of the demo program - 1111 + ======= MERGED IN content follows =============================== (line 1) + 111 - This is line one OF the demo program - 1111 + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t32 { + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) + 111 - This is line one OF the demo program - 1111 + ####### SUGGESTED CONFLICT RESOLUTION follows ################### + 111 - This is line ONE OF the demo program - 1111 + ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + 111 - This is line one of the demo program - 1111 + ======= MERGED IN content follows =============================== (line 1) + 111 - This is line ONE of the demo program - 1111 + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +fossil 3-way-merge t1 t3 t2 a32 -expectError +test merge1-2.1 {[same_file t32 a32]} +fossil 3-way-merge t1 t2 t3 a23 -expectError +test merge1-2.2 {[same_file t23 a23]} + +write_file_indented t1 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t2 { + 111 - This is line ONE of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t3 { + 111 - This is line ONE of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t23 { + 111 - This is line ONE of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +fossil 3-way-merge t1 t3 t2 a32 +test merge1-3.1 {[same_file t23 a32]} +fossil 3-way-merge t1 t2 t3 a23 +test merge1-3.2 {[same_file t23 a23]} + +write_file_indented t1 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t2 { + 000 - Zero lines added to the beginning of - 0000 + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t3 { + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t32 { + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) + ####### SUGGESTED CONFLICT RESOLUTION follows ################### + 000 - Zero lines added to the beginning of - 0000 + 111 - This is line one of the demo program - 1111 + ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + 111 - This is line one of the demo program - 1111 + ======= MERGED IN content follows =============================== (line 1) + 000 - Zero lines added to the beginning of - 0000 + 111 - This is line one of the demo program - 1111 + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t23 { + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) + 000 - Zero lines added to the beginning of - 0000 + 111 - This is line one of the demo program - 1111 + ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + 111 - This is line one of the demo program - 1111 + ======= MERGED IN content follows =============================== (line 1) + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +fossil 3-way-merge t1 t3 t2 a32 -expectError +test merge1-4.1 {[same_file t32 a32]} +fossil 3-way-merge t1 t2 t3 a23 -expectError +test merge1-4.2 {[same_file t23 a23]} + +write_file_indented t1 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t2 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 + 666 - Extra line at the end of the file wi - 6666 +} +write_file_indented t3 { + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t32 { + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 + 666 - Extra line at the end of the file wi - 6666 +} +fossil 3-way-merge t1 t3 t2 a32 +test merge1-5.1 {[same_file t32 a32]} +fossil 3-way-merge t1 t2 t3 a23 +test merge1-5.2 {[same_file t32 a23]} + +write_file_indented t1 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t2 { + 111 - This is line one of the demo program - 1111 + 333 - This is a test of the merging algohm - 3333 + 444 - If all goes well, we will be pleased - 4444 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t3 { + 111 - This is line one of the demo program - 1111 + 222 - The second line program line in code - 2222 + 333 - This is a test of the merging algohm - 3333 + 555 - we think it well and other stuff too - 5555 +} +write_file_indented t32 { + 111 - This is line one of the demo program - 1111 + 333 - This is a test of the merging algohm - 3333 + 555 - we think it well and other stuff too - 5555 +} +fossil 3-way-merge t1 t3 t2 a32 +test merge1-6.1 {[same_file t32 a32]} +fossil 3-way-merge t1 t2 t3 a23 +test merge1-6.2 {[same_file t32 a23]} + +write_file_indented t1 { + abcd + efgh + ijkl + mnop + qrst + uvwx + yzAB + CDEF + GHIJ + KLMN + OPQR + STUV + XYZ. +} +write_file_indented t2 { + abcd + efgh 2 + ijkl 2 + mnop 2 + qrst + uvwx + yzAB 2 + CDEF 2 + GHIJ 2 + KLMN + OPQR + STUV + XYZ. +} +write_file_indented t3 { + abcd + efgh + ijkl + mnop 3 + qrst 3 + uvwx 3 + yzAB 3 + CDEF + GHIJ + KLMN + OPQR + STUV + XYZ. +} +write_file_indented t23 { + abcd + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 2) + efgh 2 + ijkl 2 + mnop 2 + qrst + uvwx + yzAB 2 + CDEF 2 + GHIJ 2 + ####### SUGGESTED CONFLICT RESOLUTION follows ################### + efgh 2 + ijkl 2 + mnop 3 + qrst 3 + uvwx 3 + yzAB 3 + CDEF 2 + GHIJ 2 + ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 2) + efgh + ijkl + mnop + qrst + uvwx + yzAB + CDEF + GHIJ + ======= MERGED IN content follows =============================== (line 2) + efgh + ijkl + mnop 3 + qrst 3 + uvwx 3 + yzAB 3 + CDEF + GHIJ + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + KLMN + OPQR + STUV + XYZ. +} +fossil 3-way-merge t1 t2 t3 a23 -expectError +test merge1-7.1 {[same_file t23 a23]} + +write_file_indented t2 { + abcd + efgh 2 + ijkl 2 + mnop + qrst + uvwx + yzAB 2 + CDEF 2 + GHIJ 2 + KLMN + OPQR + STUV + XYZ. +} +write_file_indented t3 { + abcd + efgh + ijkl + mnop 3 + qrst 3 + uvwx 3 + yzAB 3 + CDEF + GHIJ + KLMN + OPQR + STUV + XYZ. +} +write_file_indented t23 { + abcd + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 2) + efgh 2 + ijkl 2 + mnop + qrst + uvwx + yzAB 2 + CDEF 2 + GHIJ 2 + ####### SUGGESTED CONFLICT RESOLUTION follows ################### + efgh 2 + ijkl 2 + mnop 3 + qrst 3 + uvwx 3 + yzAB 3 + CDEF 2 + GHIJ 2 + ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 2) + efgh + ijkl + mnop + qrst + uvwx + yzAB + CDEF + GHIJ + ======= MERGED IN content follows =============================== (line 2) + efgh + ijkl + mnop 3 + qrst 3 + uvwx 3 + yzAB 3 + CDEF + GHIJ + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + KLMN + OPQR + STUV + XYZ. +} +fossil 3-way-merge t1 t2 t3 a23 -expectError +test merge1-7.2 {[same_file t23 a23]} + +############################################################################### + +test_cleanup diff --git a/test/merge2.test b/test/merge2.test new file mode 100644 index 0000000..569ca77 --- /dev/null +++ b/test/merge2.test @@ -0,0 +1,49 @@ +# +# Copyright (c) 2006 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the delta mechanism. +# + +test_setup "" + +set filelist [lsort [glob $testdir/*]] +foreach f $filelist { + if {[file isdir $f]} continue + set base [file root [file tail $f]] + if {[string match "utf16*" $base]} continue + set f1 [read_file $f] + write_file t1 $f1 + for {set i 0} {$i<100} {incr i} { + expr {srand($i*2)} + write_file t2 [set f2 [random_changes $f1 2 4 0 0.1]] + expr {srand($i*2+1)} + write_file t3 [set f3 [random_changes $f1 2 4 2 0.1]] + expr {srand($i*2+1)} + write_file t23 [random_changes $f2 2 4 2 0.1] + expr {srand($i*2)} + write_file t32 [random_changes $f3 2 4 0 0.1] + fossil 3-way-merge t1 t2 t3 a23 + if {[regexp {<<<<< BEGIN MERGE CONFLICT:} [read_file a23]]} continue + test merge-$base-$i-23 {[same_file a23 t23]} + fossil 3-way-merge t1 t3 t2 a32 + test merge-$base-$i-32 {[same_file a32 t32]} + } +} + +############################################################################### + +test_cleanup diff --git a/test/merge3.test b/test/merge3.test new file mode 100644 index 0000000..ef9b80e --- /dev/null +++ b/test/merge3.test @@ -0,0 +1,653 @@ +# +# Copyright (c) 2009 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the 3-way merge +# + +test_setup "" + +proc merge-test {testid basis v1 v2 result {fossil_args ""}} { + write_file t1 [join [string trim $basis] \n]\n + write_file t2 [join [string trim $v1] \n]\n + write_file t3 [join [string trim $v2] \n]\n + fossil 3-way-merge t1 t2 t3 t4 {*}$fossil_args + set x [read_file t4] + regsub -all \ + {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+ \(line \d+\)} \ + $x {MINE:} x + regsub -all \ + {####### SUGGESTED CONFLICT RESOLUTION follows #+} \ + $x {BOT:} x + regsub -all \ + {\|\|\|\|\|\|\| COMMON ANCESTOR content follows \|+ \(line \d+\)} \ + $x {COM:} x + regsub -all \ + {======= MERGED IN content follows =+ \(line \d+\)} \ + $x {YOURS:} x + regsub -all \ + {>>>>>>> END MERGE CONFLICT >+} \ + $x {END} x + set x [split [string trim $x] \n] + set result [string trim $result] + if {$x!=$result} { + protOut " Expected \[$result\]" + protOut " Got \[$x\]" + test merge3-$testid 0 + } else { + test merge3-$testid 1 + } +} + +merge-test 1 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4 5 6 7 8 9 +} { + 1 2 3 4 5c 6 7 8 9 +} { + 1 2 3b 4 5c 6 7 8 9 +} + +merge-test 2 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5 6 7 8 9 +} { + 1 2 3 4 5c 6 7 8 9 +} { + 1 2 3b 4b 5c 6 7 8 9 +} +merge-test 3 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5b 6 7 8 9 +} { + 1 2 3 4 5c 6 7 8 9 +} { + 1 2 MINE: 3b 4b 5b BOT: 3b 4b 5c COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9 +} -expectError +merge-test 4 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5b 6b 7 8 9 +} { + 1 2 3 4 5c 6 7 8 9 +} { + 1 2 MINE: 3b 4b 5b 6b BOT: 3b 4b 5b 5c 6 COM: 3 4 5 6 YOURS: 3 4 5c 6 END 7 8 9 +} -expectError +merge-test 5 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5b 6b 7 8 9 +} { + 1 2 3 4 5c 6c 7c 8 9 +} { + 1 2 MINE: 3b 4b 5b 6b 7 BOT: 3b 4b 5b 5c 6c 7c COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8 9 +} -expectError +merge-test 6 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5b 6b 7 8b 9 +} { + 1 2 3 4 5c 6c 7c 8 9 +} { + 1 2 MINE: 3b 4b 5b 6b 7 BOT: 3b 4b 5b 5c 6c 7c COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8b 9 +} -expectError +merge-test 7 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5b 6b 7 8b 9 +} { + 1 2 3 4 5c 6c 7c 8c 9 +} { + 1 2 MINE: 3b 4b 5b 6b 7 8b BOT: 3b 4b 5b 5c 6c 7c 8c COM: 3 4 5 6 7 8 YOURS: 3 4 5c 6c 7c 8c END 9 +} -expectError +merge-test 8 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5b 6b 7 8b 9b +} { + 1 2 3 4 5c 6c 7c 8c 9 +} { + 1 2 MINE: 3b 4b 5b 6b 7 8b 9b BOT: 3b 4b 5b 5c 6c 7c 8c 9b COM: 3 4 5 6 7 8 9 YOURS: 3 4 5c 6c 7c 8c 9 END +} -expectError +merge-test 9 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5 6 7 8b 9b +} { + 1 2 3 4 5c 6c 7c 8 9 +} { + 1 2 3b 4b 5c 6c 7c 8b 9b +} + +merge-test 10 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5 6 7 8b 9b +} { + 1 2 3b 4b 5 6c 7c 8 9 +} { + 1 2 3b 4b 5 6c 7c 8b 9b +} +merge-test 11 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b 4b 5 6 7 8b 9b +} { + 1 2 3b 4c 5 6c 7c 8 9 +} { + 1 2 MINE: 3b 4b BOT: 3b 4c COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b +} -expectError +merge-test 12 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3b4b 5 6 7 8b 9b +} { + 1 2 3b4b 5 6c 7c 8 9 +} { + 1 2 3b4b 5 6c 7c 8b 9b +} + +merge-test 20 { + 1 2 3 4 5 6 7 8 9 +} { + 1 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 7 9 +} { + 1 3 4 5 6 7 9 +} +merge-test 21 { + 1 2 3 4 5 6 7 8 9 +} { + 1 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 9 +} { + 1 4 5 6 9 +} +merge-test 22 { + 1 2 3 4 5 6 7 8 9 +} { + 1 5 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 5 9 +} +merge-test 23 { + 1 2 3 4 5 6 7 8 9 +} { + 1 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 9 +} +merge-test 24 { + 1 2 3 4 5 6 7 8 9 +} { + 1 6 7 8 9 +} { + 1 2 3 4 9 +} { + 1 MINE: 6 7 8 BOT: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 +} -expectError +merge-test 25 { + 1 2 3 4 5 6 7 8 9 +} { + 1 7 8 9 +} { + 1 2 3 9 +} { + 1 MINE: 7 8 BOT: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 +} -expectError + +merge-test 30 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 7 9 +} { + 1 3 4 5 6 7 8 9 +} { + 1 3 4 5 6 7 9 +} +merge-test 31 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 9 +} { + 1 4 5 6 7 8 9 +} { + 1 4 5 6 9 +} +merge-test 32 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 5 6 7 8 9 +} { + 1 5 9 +} +merge-test 33 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 6 7 8 9 +} { + 1 9 +} +merge-test 34 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 9 +} { + 1 6 7 8 9 +} { + 1 MINE: 2 3 4 BOT: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9 +} -expectError +merge-test 35 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 9 +} { + 1 7 8 9 +} { + 1 MINE: 2 3 BOT: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END 9 +} -expectError + +merge-test 40 { + 2 3 4 5 6 7 8 +} { + 3 4 5 6 7 8 +} { + 2 3 4 5 6 7 +} { + 3 4 5 6 7 +} +merge-test 41 { + 2 3 4 5 6 7 8 +} { + 4 5 6 7 8 +} { + 2 3 4 5 6 +} { + 4 5 6 +} +merge-test 42 { + 2 3 4 5 6 7 8 +} { + 5 6 7 8 +} { + 2 3 4 5 +} { + 5 +} +merge-test 43 { + 2 3 4 5 6 7 8 +} { + 6 7 8 +} { + 2 3 4 5 +} { + +} +merge-test 44 { + 2 3 4 5 6 7 8 +} { + 6 7 8 +} { + 2 3 4 +} { + MINE: 6 7 8 BOT: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END +} -expectError +merge-test 45 { + 2 3 4 5 6 7 8 +} { + 7 8 +} { + 2 3 +} { + MINE: 7 8 BOT: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END +} -expectError + +merge-test 50 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 6 7 +} { + 3 4 5 6 7 8 +} { + 3 4 5 6 7 +} +merge-test 51 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 6 +} { + 4 5 6 7 8 +} { + 4 5 6 +} +merge-test 52 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 +} { + 5 6 7 8 +} { + 5 +} +merge-test 53 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 +} { + 6 7 8 +} { +} +merge-test 54 { + 2 3 4 5 6 7 8 +} { + 2 3 4 +} { + 6 7 8 +} { + MINE: 2 3 4 BOT: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END +} -expectError +merge-test 55 { + 2 3 4 5 6 7 8 +} { + 2 3 +} { + 7 8 +} { + MINE: 2 3 BOT: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END +} -expectError + +merge-test 60 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 7 9 +} { + 1 2b 3 4 5 6 7 9 +} +merge-test 61 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3b 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 9 +} { + 1 2b 3b 4 5 6 9 +} +merge-test 62 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3b 4b 5 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 2b 3b 4b 5 9 +} +merge-test 63 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3b 4b 5b 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 2b 3b 4b 5b 9 +} +merge-test 64 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3b 4b 5b 6 7 8 9 +} { + 1 2 3 4 9 +} { + 1 MINE: 2b 3b 4b 5b 6 7 8 BOT: 2b 3b 4b 4 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 +} -expectError +merge-test 65 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3b 4b 5b 6b 7 8 9 +} { + 1 2 3 9 +} { + 1 MINE: 2b 3b 4b 5b 6b 7 8 BOT: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 +} -expectError + +merge-test 70 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 7 9 +} { + 1 2b 3 4 5 6 7 8 9 +} { + 1 2b 3 4 5 6 7 9 +} +merge-test 71 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 6 9 +} { + 1 2b 3b 4 5 6 7 8 9 +} { + 1 2b 3b 4 5 6 9 +} +merge-test 72 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 2b 3b 4b 5 6 7 8 9 +} { + 1 2b 3b 4b 5 9 +} +merge-test 73 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 9 +} { + 1 2b 3b 4b 5b 6 7 8 9 +} { + 1 2b 3b 4b 5b 9 +} +merge-test 74 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 9 +} { + 1 2b 3b 4b 5b 6 7 8 9 +} { + 1 MINE: 2 3 4 BOT: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9 +} -expectError +merge-test 75 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 9 +} { + 1 2b 3b 4b 5b 6b 7 8 9 +} { + 1 MINE: 2 3 BOT: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END 9 +} -expectError + +merge-test 80 { + 2 3 4 5 6 7 8 +} { + 2b 3 4 5 6 7 8 +} { + 2 3 4 5 6 7 +} { + 2b 3 4 5 6 7 +} +merge-test 81 { + 2 3 4 5 6 7 8 +} { + 2b 3b 4 5 6 7 8 +} { + 2 3 4 5 6 +} { + 2b 3b 4 5 6 +} +merge-test 82 { + 2 3 4 5 6 7 8 +} { + 2b 3b 4b 5 6 7 8 +} { + 2 3 4 5 +} { + 2b 3b 4b 5 +} +merge-test 83 { + 2 3 4 5 6 7 8 +} { + 2b 3b 4b 5b 6 7 8 +} { + 2 3 4 5 +} { + 2b 3b 4b 5b +} +merge-test 84 { + 2 3 4 5 6 7 8 +} { + 2b 3b 4b 5b 6 7 8 +} { + 2 3 4 +} { + MINE: 2b 3b 4b 5b 6 7 8 BOT: 2b 3b 4b 4 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END +} -expectError +merge-test 85 { + 2 3 4 5 6 7 8 +} { + 2b 3b 4b 5b 6b 7 8 +} { + 2 3 +} { + MINE: 2b 3b 4b 5b 6b 7 8 BOT: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END +} -expectError + +merge-test 90 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 6 7 +} { + 2b 3 4 5 6 7 8 +} { + 2b 3 4 5 6 7 +} +merge-test 91 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 6 +} { + 2b 3b 4 5 6 7 8 +} { + 2b 3b 4 5 6 +} +merge-test 92 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 +} { + 2b 3b 4b 5 6 7 8 +} { + 2b 3b 4b 5 +} +merge-test 93 { + 2 3 4 5 6 7 8 +} { + 2 3 4 5 +} { + 2b 3b 4b 5b 6 7 8 +} { + 2b 3b 4b 5b +} +merge-test 94 { + 2 3 4 5 6 7 8 +} { + 2 3 4 +} { + 2b 3b 4b 5b 6 7 8 +} { + MINE: 2 3 4 BOT: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END +} -expectError +merge-test 95 { + 2 3 4 5 6 7 8 +} { + 2 3 +} { + 2b 3b 4b 5b 6b 7 8 +} { + MINE: 2 3 BOT: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END +} -expectError + +merge-test 100 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3 4 5 7 8 9 a b c d e +} { + 1 2b 3 4 5 7 8 9 a b c d e +} { + 1 2b 3 4 5 7 8 9 a b c d e +} +merge-test 101 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3 4 5 7 8 9 a b c d e +} { + 1 2b 3 4 5 7 8 9 +} { + 1 2b 3 4 5 7 8 9 a b c d e +} +merge-test 102 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3 4 5 7 8 9 +} { + 1 2b 3 4 5 7 8 9 a b c d e +} { + 1 2b 3 4 5 7 8 9 a b c d e +} +merge-test 103 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 7 8 9b +} { + 1 2 3 4 5 7 8 9b a b c d e +} { + 1 2 3 4 5 7 8 MINE: 9b BOT: 9b a b c d e COM: 9 YOURS: 9b a b c d e END +} -expectError +merge-test 104 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2 3 4 5 7 8 9b a b c d e +} { + 1 2 3 4 5 7 8 9b +} { + 1 2 3 4 5 7 8 MINE: 9b a b c d e BOT: 9b COM: 9 YOURS: 9b END +} -expectError + +############################################################################### + +test_cleanup diff --git a/test/merge4.test b/test/merge4.test new file mode 100644 index 0000000..629ba9c --- /dev/null +++ b/test/merge4.test @@ -0,0 +1,105 @@ +# +# Copyright (c) 2009 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the 3-way merge +# + +test_setup "" + +proc merge-test {testid basis v1 v2 result1 result2 {fossil_args ""}} { + write_file t1 [join [string trim $basis] \n]\n + write_file t2 [join [string trim $v1] \n]\n + write_file t3 [join [string trim $v2] \n]\n + fossil 3-way-merge t1 t2 t3 t4 {*}$fossil_args + fossil 3-way-merge t1 t3 t2 t5 {*}$fossil_args + set x [read_file t4] + regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<< \(line \d+\)} $x {>} x + regsub -all {####### SUGGESTED CONFLICT RESOLUTION.*##} $x {#} x + regsub -all {\|\|\|\|\|\|\|.*======= \(line \d+\)} $x {=} x + regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x + set x [split [string trim $x] \n] + set y [read_file t5] + regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<< \(line \d+\)} $y {>} y + regsub -all {####### SUGGESTED CONFLICT RESOLUTION.*##} $y {#} y + regsub -all {\|\|\|\|\|\|\|.*======= \(line \d+\)} $y {=} y + regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $y {<} y + set y [split [string trim $y] \n] + set result1 [string trim $result1] + if {$x!=$result1} { + protOut " Expected \[$result1\]" + protOut " Got \[$x\]" + test merge4-$testid 0 + } else { + set result2 [string trim $result2] + if {$y!=$result2} { + protOut " Expected \[$result2\]" + protOut " Got \[$y\]" + test merge4-$testid 0 + } else { + test merge4-$testid 1 + } + } +} + +merge-test 1000 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3b 4b 5 6b 7b 8b 9 +} { + 1 2 3 4c 5c 6c 7 8 9 +} { + 1 > 2b 3b 4b 5 6b 7b 8b # 2b 3b 4c 5c 6c 7b 8b = 2 3 4c 5c 6c 7 8 < 9 +} { + 1 > 2 3 4c 5c 6c 7 8 # 2b 3b 4b 5c 6b 7b 8b = 2b 3b 4b 5 6b 7b 8b < 9 +} -expectError +merge-test 1001 { + 1 2 3 4 5 6 7 8 9 +} { + 1 2b 3b 4 5 6 7b 8b 9 +} { + 1 2 3 4c 5c 6c 7 8 9 +} { + 1 2b 3b 4c 5c 6c 7b 8b 9 +} { + 1 2b 3b 4c 5c 6c 7b 8b 9 +} +merge-test 1002 { + 2 3 4 5 6 7 8 +} { + 2b 3b 4b 5 6b 7b 8b +} { + 2 3 4c 5c 6c 7 8 +} { + > 2b 3b 4b 5 6b 7b 8b # 2b 3b 4c 5c 6c 7b 8b = 2 3 4c 5c 6c 7 8 < +} { + > 2 3 4c 5c 6c 7 8 # 2b 3b 4b 5c 6b 7b 8b = 2b 3b 4b 5 6b 7b 8b < +} -expectError +merge-test 1003 { + 2 3 4 5 6 7 8 +} { + 2b 3b 4 5 6 7b 8b +} { + 2 3 4c 5c 6c 7 8 +} { + 2b 3b 4c 5c 6c 7b 8b +} { + 2b 3b 4c 5c 6c 7b 8b +} + +############################################################################### + +test_cleanup diff --git a/test/merge5.test b/test/merge5.test new file mode 100644 index 0000000..e97ae71 --- /dev/null +++ b/test/merge5.test @@ -0,0 +1,319 @@ +# +# Copyright (c) 2010 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the "merge" command +# + +if {! $::QUIET} { + puts "Skipping Merge5 tests" +} +protOut { +fossil sqlite3 --no-repository reacts badly to SQL dumped from +repositories created from fossil older than version 2.0. +} +#test merge5-sqlite3-issue false knownBug +test_cleanup_then_return + +# Verify the results of a check-out +# +proc checkout-test {testid expected_content} { + set flist {} + foreach {status filename} [exec $::fossilexe ls -l] { + if {$status!="DELETED"} {lappend flist $filename} + } + eval fossil sha1sum [lsort $flist] + global RESULT + regsub -all {\n *} [string trim $expected_content] "\n " expected + regsub -all {\n *} [string trim $RESULT] "\n " result + if {$result!=$expected} { + protOut " Expected:\n $expected" + protOut " Got:\n $result" + test merge5-$testid 0 + } else { + test merge5-$testid 1 + } +} + +require_no_open_checkout; test_setup "" + +# Construct a test repository +# +exec $::fossilexe sqlite3 --no-repository m5.fossil <$testdir/${testfile}_repo.sql +fossil rebuild m5.fossil +fossil open m5.fossil +fossil user default drh --user drh +fossil update baseline +checkout-test 10 { + da5c8346496f3421cb58f84b6e59e9531d9d424d one.txt + ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt + 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt +} + +# Update to the tip of the trunk +# +fossil update trunk +checkout-test 20 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Merge in the change that adds file four.txt +# +fossil merge br1 +checkout-test 30 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Undo the merge. Verify restoration of former state. +# +fossil undo +checkout-test 40 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Now switch to br1 then merge in the trunk. Verify that the result +# is the same as merging br1 into trunk. +# +fossil update br1 +fossil merge trunk +checkout-test 50 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil undo +fossil update trunk +checkout-test 60 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Go back to the tip of the trunk and merge branch br1 again. This +# time do a check-in of the merge. Verify that the same content appears +# after the merge. +# +fossil update chng3 +fossil merge br1 +checkout-test 70 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil commit -tag m1 -m {merge with br1} -nosign -f +checkout-test 71 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil update chng3 +checkout-test 72 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil update m1 +checkout-test 73 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Merge br2 into the trunk. br2 contains some independent change to the +# two.txt file. Verify that these are merge in correctly. +# +fossil update m1 +fossil merge br2 +checkout-test 80 { + 8f09bc55a60eb8ca06f10a3b577aafa869b31695 five.txt + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + 68eeee8b843eaea76e33d3911f416b745d0e5e5c two.txt +} +fossil undo +checkout-test 81 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Now merge trunk into br2. Verify that the same set of changes result. +# +fossil update br2 +fossil merge trunk +checkout-test 90 { + 8f09bc55a60eb8ca06f10a3b577aafa869b31695 five.txt + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + 68eeee8b843eaea76e33d3911f416b745d0e5e5c two.txt +} +fossil undo +checkout-test 91 { + 8f09bc55a60eb8ca06f10a3b577aafa869b31695 five.txt + da5c8346496f3421cb58f84b6e59e9531d9d424d one.txt + ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt + 85286cb3bc6d9e6f2f586eb5532f6065678f75b9 two.txt +} + +# Starting from chng3, merge in br4. The one file is deleted from br4, so +# the merge should cause the one file to disappear from the checkout. +# +fossil update chng3 +checkout-test 100 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil merge br4 +checkout-test 101 { + 6e167b139c294bed560e2e30b352361b101e1f39 four.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil undo +checkout-test 102 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Do the same merge of br4 into chng3, but this time check it in as a new +# branch. +# +fossil update chng3 +fossil merge br4 +fossil commit -nosign -branch br4-b -m {merge in br4} -tag m2 +checkout-test 110 { + 6e167b139c294bed560e2e30b352361b101e1f39 four.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} + +# Branches br1 and br4 both add file four.txt. So if we merge them together, +# the version of file four.txt in the original should be preserved. +# +fossil update br1 +checkout-test 120 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + da5c8346496f3421cb58f84b6e59e9531d9d424d one.txt + ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt + 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt +} +fossil merge br4 -expectError +checkout-test 121 { + 35815cf5804e8933eab64ae34e00bbb381be72c5 four.txt + ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt + 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt +} +fossil undo +fossil update br4 +checkout-test 122 { + 6e167b139c294bed560e2e30b352361b101e1f39 four.txt + ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt + 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt +} +fossil merge br1 -expectError +checkout-test 123 { + 6e167b139c294bed560e2e30b352361b101e1f39 four.txt + ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt + 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt +} +fossil undo + +# Merge br5 (which includes a file rename) into chng3 +# +fossil update chng3 +checkout-test 130 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil merge br5 +checkout-test 131 { + 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt + 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt + e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt +} +fossil undo +checkout-test 132 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil merge br5 +checkout-test 133 { + 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt + 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt + e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt +} +fossil commit -nosign -m {merge with rename} -branch {trunk+br5} +checkout-test 134 { + 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt + 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt + e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt +} +fossil update chng3 +checkout-test 135 { + 6f525ab779ad66e24474d845c5fb7938be42d50d one.txt + 64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b three.txt + b262fee89ed8a27a23a5e09d3917e0bebe22cd24 two.txt +} +fossil update trunk+br5 +checkout-test 136 { + 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt + 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt + e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt +} + +# Merge the chng3 check-in into br5, verifying that the change to two.txt +# from chng3 are applies to two-rename.txt in br5. +# +fossil update br5 +checkout-test 140 { + e866bb885d5184cba497cfb6a4eb281688519521 one.txt + e09593950837f76e70ca2f8ff2272ae3df0ba017 three.txt + 5ebb3c9ad50740a7382902657b84a6105c32fc7b two-rename.txt +} +fossil merge chng3 +checkout-test 141 { + 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt + 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt + e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt +} +fossil commit -nosign -m {change to two} -branch br5-2 +checkout-test 142 { + 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt + 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt + e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt +} + +############################################################################### + +test_cleanup diff --git a/test/merge5_repo.sql b/test/merge5_repo.sql new file mode 100644 index 0000000..8921f09 --- /dev/null +++ b/test/merge5_repo.sql @@ -0,0 +1,391 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE blob( + rid INTEGER PRIMARY KEY, + rcvid INTEGER, + size INTEGER, + uuid TEXT UNIQUE NOT NULL, + content BLOB, + CHECK( length(uuid)==40 AND rid>0 ) +); +INSERT INTO "blob" VALUES(1,1,160,'85d5623f065ba80b20a035dcb4f9aea045215406',X'000000A0789C1DC8BD0E82301000E0BD4F71334993FE1CB465D507300617C352AED7D0208D011C787BA3E3F75DA0D47294F81A775EDFC739EE34332DB2547105A3B492DA48AD078D7D1B7A6BC54DDC21A14E9E52F059A9C928E4E0950AC133658FC6B118A099B6586986068EED5397DFECE72AFF80463C206DB37802C69CACCB31B8EC983B424D2D2361B04645EE92F802B1932DED'); +INSERT INTO "blob" VALUES(2,2,10,'da5c8346496f3421cb58f84b6e59e9531d9d424d',X'0000000A789C73E472E272E672E172E5020008CA0182'); +INSERT INTO "blob" VALUES(3,2,10,'ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4',X'0000000A789CF3E6F2E1F2E5F2E3F2E7020009F601B4'); +INSERT INTO "blob" VALUES(4,2,10,'278a402316510f6ae4a77186796a6bde78c7dbc1',X'0000000A789C73E372E7F2E0F2E4F2E202000960019B'); +INSERT INTO "blob" VALUES(5,2,325,'69cc5363f67013c09bf506e3fe9533c32d0bc1ef',X'000000AF789C05C1C10AC2300C00D07BBF621FB0439A365B3B2F0351F426CA2EB24BBAA4AC3005D7FD3FBE47645EC3B96191B91EEBAE3AD7F22D47E16DAEB96C5AEFE3B5F5030E00388DF6D1DADF1048A84397A1A3C401120283235992CF9195C1135AF2D09967B308E788392FA187B8B0042F2E893AC60E803499A9917D35EF2670C09853E0A8092893EF859CB33D6A8414351AFCF0ED72FA03D5E231F2'); +INSERT INTO "blob" VALUES(6,3,190,'3bfa21d09f8718adc3195848d57114e1fbf564fe',X'000000BE789C8DCC3B0EC2300C00D03DA7C88E2AF9A32475678E5016C49238B6400206D285DB036261E400EFED2301C2843421AE9816A02595B0C65DAF9BC52CAA89337B2E80AC20CD1364633749CCCAD4A1299AFF24A7F15D003ECB78DEA656875D2FF7FFB77088FD710EC758BA6095590C082BEAECEC4AC58CDEBEA2617801EE253190'); +INSERT INTO "blob" VALUES(7,4,10,'35815cf5804e8933eab64ae34e00bbb381be72c5',X'0000000A789C0BE00AE40AE20AE60AE102000A8C01CD'); +INSERT INTO "blob" VALUES(8,4,364,'341db367709dc7bc5046ab4fda4f7d9423118cba',X'0000016C789C35CE3B4E44310C85E1FEAE221B1864C78F24B4206A84A0413476EC888A918641B07CEE0CA23D3A9FF4DF158B78FB5CC7AFD3CDF9E7BCDD970A0807AC07C467945BE05B94EDA1FC1F0A4947994B3A70F64194E6CA96C409E0EED4D1B3D57931C78FBC9230999D5879E822AE385DFAEAEC9A327208618CE0CAB193F3FB29FF50C6BEE0885635B0D1C21EBED886C1EA821C6694348D2FE8FB7825B57563A8842A084B2DD95AC3AE6DA8A947B63E5BF8C4EDB1E8985348696903A409C3978026AD4B0F4DAA01FB31D7F65422C1AC73A4A3D5BD7CEF07016B16BBB5C9DB4B89D3FBF65A6C7873C33052034A6D94E82CAED85BA4ACED1765FC64F9'); +INSERT INTO "blob" VALUES(9,5,294,'9223b4cad40c0bc997b747fe4eee586559a43815',X'00000126789C8D8E310E83300C45774E91B955243B714860EE11E85275B16322A4AA0C0186DEBEA00E5DD9FEF2FE7B37E300C1A2B38803861EA8F7D40CE62295E73C194FA8E2DB18A1D31C2507A096858A3295A81D398F98B2B0918A07B67CDE769FA7B99DB92AAFE379D1BFF7B9FC8231EC2FF630AF759B5FE7DD77A3756A1EC68D0C3E69424DA20E3460804C259172F15E52F305DF884EE5'); +INSERT INTO "blob" VALUES(10,6,10,'8f09bc55a60eb8ca06f10a3b577aafa869b31695',X'0000000A789C0BE50AE30AE78AE08AE402000B2201E6'); +INSERT INTO "blob" VALUES(11,6,426,'3d5bce2e44a6b39205eb514c581aa41d86f48540',X'00000116789C458ECB4A04311444F7F98AAC075BEE23B949DA8DA01F203A832082E471C30C6A2FBA47D1BF37BA7157A7288A23DDBCCC3736B7F6BCF5D3A75E9EBFCEE6D612204C4813E21EFD0C7E266AD78F177C9829C4EC8018C52374C9EA7208182524C9529A8658432B15CD9D9554AB67E12E01902BA4D23D8872D7E4992B538331D46EEE6D23AA320E1CE4C6B1A5CCDDA973181C6BF705CCDEEECA9A977AB43B5B56FAE5EDFB7D1AD1EE064C7F90377D3B2DFADF9CD78FE575E0C1B6F5689E6C57284961887A14A89A628B340C2825E118C020A6F0E0AE7E00A7744B2A'); +INSERT INTO "blob" VALUES(12,7,10,'c6536e40b3d4755ead483c2e0fb2f16ecb751b6a',X'0000000A789C33E032E432E232E632E1020006CC012D'); +INSERT INTO "blob" VALUES(13,7,424,'b95701e0b73e5ebf452a9a7ae00360bf7fd187fd',X'000001A8789C4590414F83310886EFDFAFE879C90C9496B65E359E8DD18BF10285668B3A936F33EABFB753136FBCC003BC5C05317B3A1EF79F17A7CFD3721D22206C316E11EF315F025FC6B8DC84B7839FEBC124F74A8953E3412962D75C474DCA9E9BB74C68CD524C3691BF91A17326F6044A964ACE2E962AF5E830340E64EF5A322ACB444EBBD57FF7B8CD21D8AC44362C34B09A8E244D60D48CC944C8A94B3A431F6F3F482C55124442CE0883C5939482954B6361352FB517D38ECB6DE0D6FB3C8A061740EAD0746460A771B6409DA2C16CF4B1DC85311D4D9AA4E4DEB21924D10AAA0834AD132CF761A3AB1CFA2E6C82AE74D6C7AFD7ED0CC3668AED8F90A3BFEC0FFE9F39ADEF87E7291F82ADBBE5312895341D420637C74AB5CD6F5185E23AC41B2FDF3224768A'); +INSERT INTO "blob" VALUES(14,8,11,'6f525ab779ad66e24474d845c5fb7938be42d50d',X'0000000B789C73E4728AE072E672E172E502000C1801DA'); +INSERT INTO "blob" VALUES(15,8,319,'c19f6ae71a35cddef0d5de3e1e6109c4378c8215',X'000000E0789C0DCA314E04310C05D03EA7C80158E41F27F6646890587A844048681B274E986A4762B6A0E2ECF0EA977FC3B63EC5BED9F56B1C97E3B65F8EFD3AEE6F3FB7708E894027A413F086B292AE00F6C7ED2E7DAC4917CB94185240536C6453C5225AC5A4F9D0A5ABB78EF012A5F65E58788A12B8536DB3900C9EA316E6CEC9E93F8E195EA361641573481EA5D6E900235B422FD49435BC47FFDEC2672469A9CEC98AAEE685672ECD45B28FEA8B590BA99D9FBD3DFC010C0C3CFF'); +INSERT INTO "blob" VALUES(16,9,11,'b262fee89ed8a27a23a5e09d3917e0bebe22cd24',X'0000000B789C73E372E7F288E0F2E4F2E202000C5A01F3'); +INSERT INTO "blob" VALUES(17,9,319,'41a02f2b2277d771d85e7f1202c82d4d6675662f',X'000000D8789C0DCE3B4E03410C00D07E4EB107D820DB63CF8F668B488882068890E8BCB6478806258A142ACE4E0EF0A4C77FE96983F56DDC7E1EAEBFD7745C08100E4807C47794017590206CDFAB8F7062C7EE958A63CD139BEF93B52BCC26C8AE9A239BF265A39715CFC3B0CFA25151B3987B4C70F1C8815110BA71AECD1AA1A4D785F5AE4929B07397CADE729F6462358A36F3745AFCF2953E17C9AD30766AA5CE3DD8E27EA1BD548FD80D9C533E3F9FE6C7E33F8FCE3AED'); +INSERT INTO "blob" VALUES(18,10,187,'6c22c86ee8a603f5e18171efb6ff571b59e35cf3',X'000000BB789C8DCCAD0EC230140650DFA7A8274BFAB5B4B7ADE611862198EEFE30038261787B9843A24F724E3E068409710266E41E6A4776B33FC878A967342B4309236516510B924593420B42E363A2CA3522FF24D76D5FA803FBB2BDEF13AF8F1BFEAEDCD9CB7375176F45D8961C858C9651BED86C080189381621F701B249318A'); +INSERT INTO "blob" VALUES(19,11,187,'8b9f82378ea7a5f9ef8e80d31929f6dfab988acc',X'000000BB789C8DCC3D0EC2300C06D03DA7C88E22D95F623BEACC11CA8258F24B1718280BB747DD18790778670F620A8CC0BCB22C9497486EF5A75EDEC3272E84890A987533EE59864D06A165F4D4554D54317F92DB7E2CB6408E65FF3C42DB9E77FC5DB98BEFAFCD5DBD0C9E604819AC31D5A489F2906AA5C5AAA4C57D01A0C52E74'); +INSERT INTO "blob" VALUES(20,12,11,'64a8a5c7320fccfa4b2e5dfc5fd20a5381a86c5b',X'0000000B789CF3E6F2E1F2E5F28BE0F2E702000CA7020C'); +INSERT INTO "blob" VALUES(21,12,321,'5a71ecd64585155b076a4f1e4d489eb5fe3d05f4',X'00000141789C3D8F314E04310C45FB9C221758643B719C6C0BA246081A44E3C40E53ED48BB23C1F1095B50B8F8FA7A4FDF8F716C7AF9F2DBE7EDD8D76D57F787E3E7084F9100E18474427C433E239D81C273DC2FF73E96C9C4DA459A5A294E394BB69A79F0ECD252ED9EC9186C21FFD258B256E52189608E31357772B6B91823504E15B596C1FD0FFADEEF48A742D3BD36B7AA244A49D9A1596A280EDDBB130DA31C5E6246059AD489444C04ADB2CB44021A952CAF99C265D9C2EBB2226371186AA4C35704D7C252C0B06A1FE13DDA750B1F9111E6C4543CF1C4A1136606582F0FE406D424FC021EAB59DA'); +INSERT INTO "blob" VALUES(22,13,187,'a2c1640c98b3059a83df0b597d673ad073b782de',X'000000BB789C8DCC310EC2300C00C03DAFC88E22D9899DA49D794259108B93D874818176E1F7805818994FBAA38F80103006C40579C63863718B3F0CD9D5B314D43E327165646E50B290A1D2A03A6963D334808D7E92CBF65D207E96ED790B7DBD5FD3DF953BF9F158DDD96B1EB1D91B92285649B917AD5627A8066842EE05469C30D4'); +INSERT INTO "blob" VALUES(23,14,10,'6e167b139c294bed560e2e30b352361b101e1f39',X'0000000A789C33E532E332E7B2E0B2E4020007620146'); +INSERT INTO "blob" VALUES(24,14,388,'8015e80a2391d4497530b5d0f36689f359e374ba',X'00000184789C4590314FC4300C85F7FE8ACC2715D971E234C7086246E8585017277174086851DBD3C1BF27BD85CDCFF6A7F7EC075396F97B5CE749EFC7554A19D749AFE35AE7CBD23D1A0B083DDA1EF184FE8874F4DC3D997D78B7FD6C86153924A4986D74498B6750AB0489BC25C684808A956263B6F3A27A83B45857309660B960A08A4349D54914A88347574448298BDBA1EB7C436C18C48125648F5059D449083870882C9C8A862187923276CF8663CE9E982A0740CA1053F5C04A55A327CA640BB445ADDD8B69E611497373AF425407B0FB19A145C6C04CDDC91CD222533E9B83498BDBF5FAFBD5B7D21C9AE86F4256FD7C9FF4BFB32D97E9A3C9D7F6DA73F7666A96907CB351CB9A23D89CAB44675B50715CA8FB033C856E21'); +INSERT INTO "blob" VALUES(25,15,11,'e866bb885d5184cba497cfb6a4eb281688519521',X'0000000B789C73E472E272E672E1728DE002000AF201DA'); +INSERT INTO "blob" VALUES(26,15,372,'b882b17dc56af1e0297bf8a57c9d15050215c64a',X'00000174789C458E414B04310C85EFF32B7A5E1869D23669BD2A9E45D68B78499BD41175166657D47F6F7711841CF2F2DE47DE8D6B8BAC2FF67C3CAC36DD3AF4E067C019600FE97A0CD274E7867775FA3E39CB44B5E69C34418EAD4A2CDC7A25895631030D074A4218C869D9EC0F528C0A451949814387ACB54729E2FB88471509169AC433F475B820C859A2C70094C077128BC20C99B8905055E3DC586B83E9DE51692D050A9DD84368BED49E3C59E85652082DA0FA11B43E3D38EB297266D4D414C427E30E56C2E8D0A1F9D4A7BDDBD54DD6B6B89DAB5B3AEBE3CFC73C56B71B62BE0839DAFBEB6AFF97D3F6B9BE0DF9E8745BA6A7F1463B76C4AC68218D9A1AA216C2D822D4C63CFD0205E667AF'); +INSERT INTO "blob" VALUES(27,16,11,'e09593950837f76e70ca2f8ff2272ae3df0ba017',X'0000000B789CF38EE0F2E1F2E5F2E3F2E702000DB2020C'); +INSERT INTO "blob" VALUES(28,16,341,'9df70ff13b57e70ea2de63f655eb72df7b83121a',X'000000EF789C0DCD3D4E03311040E1DEA7F001089AF17AFE360D52525220040D8A846C8FAD5004A4CD8AE5F86CF99AEFD173B8CDA7D8FD6BBDDCD7EBD2FBF1725FFA77B9F5BDB79F708E09100E980E886F4833F28C80BF4FFE90C69C444B86342113C2E0D273114165312E5CBD8B36F1DA306E71B71ED7BF35BCC4AA9A2A8A37E232B04332A9430B493347028284D43897F01AD5D4B077A326640C5981477611A324FB7A84F7E8CB357C441BD51C9407541D0A669433FBA05C26622E14A6069F1B1FFF019008411F'); +INSERT INTO "blob" VALUES(29,17,11,'5ebb3c9ad50740a7382902657b84a6105c32fc7b',X'0000000B789C73E372E7F2E0F28CE4F2E202000C0101F4'); +INSERT INTO "blob" VALUES(30,17,322,'94bd3e6b45cc15e86cc76ecfd2207fddbb675b15',X'00000142789C3DCE314E44310C04D0FE9F221758643B711C6F0BA246081A441327B696825D69F9121C9F8010F5F8CDF836F97CDB5F3FF6CFCBE1EAE7FEEEDB5D224038201D109F908F588F85B6FB7439FBCDFEB5276FB59AB5C693B19561BDA88CB0DA8B1B35AC2B4165C245F6D3D5FF10286B56869625A4BAC0E8142D8248A87B9E01D601E507FDBFF22BD9CDF2D03E19A44097DC48812A8BB5D22B028F4C31C4B687A4330422301BCB5AF04ED36B8ECAAB436885D63212F6ED31E56985D1EB2A96A22DFA8800CC6C485A88FAF69CE6F5B4BD24556990111A87AECBEEEAB50C5F8EAB308FED1BE1CB587B'); +INSERT INTO "blob" VALUES(31,18,11,'85286cb3bc6d9e6f2f586eb5532f6065678f75b9',X'0000000B789C73E372E7F2E0F2E4F28AE402000BA301F4'); +INSERT INTO "blob" VALUES(32,18,360,'333c4d56d218735e20565944b50202f24827e3b8',X'00000168789C25CF3D4E43311004E0DEA7F00582BCDE1FAFD382A8118206D1ECDA5E250D91C213E1F83C9476349F34F398D73C6F9FDFDBED929E722D500E500F006F20472A47C4F49CE3FCB31EB6DF2D6B94EE83D9A42CD76145028AA1736B66612ADD11A4F36E2E5F77328D8722097509A40AC35943C965715F9D11669F5469EE643B5DD71DADB927D067AB32A161804E0FB26E259481A6192E1C46FFE876B94FE3AA321C7DC8EC4BA206AB2C67C61A5284A56934F69E5E324EF6B1EA223271ECB5F0DE031AAC604630558294A9A4D76C4B54753F568B8B16F4D5102946AD4EA1BAD27B9ED753FAC80338F6EBB37A31F568AD888A556519A32B78FA037C076278'); +CREATE TABLE delta( + rid INTEGER PRIMARY KEY, + srcid INTEGER NOT NULL REFERENCES blob +); +INSERT INTO "delta" VALUES(5,8); +INSERT INTO "delta" VALUES(11,32); +INSERT INTO "delta" VALUES(15,17); +INSERT INTO "delta" VALUES(17,21); +INSERT INTO "delta" VALUES(28,30); +CREATE TABLE rcvfrom( + rcvid INTEGER PRIMARY KEY, + uid INTEGER REFERENCES user, + mtime DATETIME, + nonce TEXT UNIQUE, + ipaddr TEXT +); +INSERT INTO "rcvfrom" VALUES(1,1,2455542.12469579,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(2,1,2455542.12638891,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(3,1,2455542.12705387,NULL,'127.0.0.1'); +INSERT INTO "rcvfrom" VALUES(4,1,2455542.12796271,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(5,1,2455542.12818105,NULL,'127.0.0.1'); +INSERT INTO "rcvfrom" VALUES(6,1,2455542.12873891,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(7,1,2455542.1294266,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(8,1,2455542.12999842,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(9,1,2455542.13015219,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(10,1,2455542.13073123,NULL,'127.0.0.1'); +INSERT INTO "rcvfrom" VALUES(11,1,2455542.13090438,NULL,'127.0.0.1'); +INSERT INTO "rcvfrom" VALUES(12,1,2455542.1333612,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(13,1,2455542.13353873,NULL,'127.0.0.1'); +INSERT INTO "rcvfrom" VALUES(14,1,2455542.13467894,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(15,1,2455542.13571911,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(16,1,2455542.13623403,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(17,1,2455542.13660848,NULL,NULL); +INSERT INTO "rcvfrom" VALUES(18,1,2455542.19483546,NULL,NULL); +CREATE TABLE user( + uid INTEGER PRIMARY KEY, + login TEXT, + pw TEXT, + cap TEXT, + cookie TEXT, + ipaddr TEXT, + cexpire DATETIME, + info TEXT, + photo BLOB +); +INSERT INTO "user" VALUES(1,'drh','efbbd0','s',NULL,NULL,NULL,'',NULL); +INSERT INTO "user" VALUES(2,'anonymous','42568D1800352E28','ghmncz',NULL,NULL,NULL,'Anon',NULL); +INSERT INTO "user" VALUES(3,'nobody','','jor',NULL,NULL,NULL,'Nobody',NULL); +INSERT INTO "user" VALUES(4,'developer','','dei',NULL,NULL,NULL,'Dev',NULL); +INSERT INTO "user" VALUES(5,'reader','','kptw',NULL,NULL,NULL,'Reader',NULL); +CREATE TABLE config( + name TEXT PRIMARY KEY NOT NULL, + value CLOB, + CHECK( typeof(name)='text' AND length(name)>=1 ) +); +INSERT INTO "config" VALUES('server-code','48d0adf1afd58dae13c5b70ff7aff208fb8b9f53'); +INSERT INTO "config" VALUES('project-code','8201587e22864f2fe6b8eb623626de6f9f747058'); +INSERT INTO "config" VALUES('autosync','1'); +INSERT INTO "config" VALUES('localauth','0'); +INSERT INTO "config" VALUES('project-name','Test Case 1'); +INSERT INTO "config" VALUES('project-description','Fossil repository for testing'); +INSERT INTO "config" VALUES('index-page','/timeline'); +INSERT INTO "config" VALUES('content-schema','1'); +INSERT INTO "config" VALUES('aux-schema','2010-11-24'); +CREATE TABLE shun(uuid UNIQUE); +CREATE TABLE private(rid INTEGER PRIMARY KEY); +CREATE TABLE reportfmt( + rn integer primary key, + owner text, + title text, + cols text, + sqlcode text +); +INSERT INTO "reportfmt" VALUES(1,NULL,'All Tickets','#ffffff Key: +#f2dcdc Active +#e8e8e8 Review +#cfe8bd Fixed +#bde5d6 Tested +#cacae5 Deferred +#c8c8c8 Closed','SELECT + CASE WHEN status IN (''Open'',''Verified'') THEN ''#f2dcdc'' + WHEN status=''Review'' THEN ''#e8e8e8'' + WHEN status=''Fixed'' THEN ''#cfe8bd'' + WHEN status=''Tested'' THEN ''#bde5d6'' + WHEN status=''Deferred'' THEN ''#cacae5'' + ELSE ''#c8c8c8'' END AS ''bgcolor'', + substr(tkt_uuid,1,10) AS ''#'', + datetime(tkt_mtime) AS ''mtime'', + type, + status, + subsystem, + title +FROM ticket'); +CREATE TABLE concealed( + hash TEXT PRIMARY KEY, + content TEXT +); +CREATE TABLE filename( + fnid INTEGER PRIMARY KEY, + name TEXT UNIQUE +); +INSERT INTO "filename" VALUES(1,'four.txt'); +INSERT INTO "filename" VALUES(2,'one.txt'); +INSERT INTO "filename" VALUES(3,'three.txt'); +INSERT INTO "filename" VALUES(4,'two.txt'); +INSERT INTO "filename" VALUES(5,'five.txt'); +INSERT INTO "filename" VALUES(6,'six.txt'); +INSERT INTO "filename" VALUES(7,'two-rename.txt'); +CREATE TABLE mlink( + mid INTEGER REFERENCES blob, + pid INTEGER REFERENCES blob, + fid INTEGER REFERENCES blob, + fnid INTEGER REFERENCES filename, + pfnid INTEGER REFERENCES filename +); +INSERT INTO "mlink" VALUES(8,0,7,1,0); +INSERT INTO "mlink" VALUES(5,0,2,2,0); +INSERT INTO "mlink" VALUES(5,0,3,3,0); +INSERT INTO "mlink" VALUES(5,0,4,4,0); +INSERT INTO "mlink" VALUES(11,0,10,5,0); +INSERT INTO "mlink" VALUES(13,0,12,6,0); +INSERT INTO "mlink" VALUES(21,3,20,3,0); +INSERT INTO "mlink" VALUES(17,4,16,4,0); +INSERT INTO "mlink" VALUES(15,2,14,2,0); +INSERT INTO "mlink" VALUES(24,0,23,1,0); +INSERT INTO "mlink" VALUES(24,2,0,2,0); +INSERT INTO "mlink" VALUES(26,2,25,2,0); +INSERT INTO "mlink" VALUES(30,4,29,7,0); +INSERT INTO "mlink" VALUES(28,3,27,3,0); +INSERT INTO "mlink" VALUES(28,4,4,7,4); +INSERT INTO "mlink" VALUES(28,4,0,4,0); +INSERT INTO "mlink" VALUES(32,4,31,4,0); +CREATE TABLE plink( + pid INTEGER REFERENCES blob, + cid INTEGER REFERENCES blob, + isprim BOOLEAN, + mtime DATETIME, + UNIQUE(pid, cid) +); +INSERT INTO "plink" VALUES(5,8,1,2455542.12795139); +INSERT INTO "plink" VALUES(1,5,1,2455542.12638889); +INSERT INTO "plink" VALUES(5,11,1,2455542.12873843); +INSERT INTO "plink" VALUES(5,13,1,2455542.1294213); +INSERT INTO "plink" VALUES(17,21,1,2455542.13335648); +INSERT INTO "plink" VALUES(15,17,1,2455542.13015046); +INSERT INTO "plink" VALUES(5,15,1,2455542.12998843); +INSERT INTO "plink" VALUES(5,24,1,2455542.13467593); +INSERT INTO "plink" VALUES(5,26,1,2455542.13571759); +INSERT INTO "plink" VALUES(28,30,1,2455542.13659722); +INSERT INTO "plink" VALUES(26,28,1,2455542.13622685); +INSERT INTO "plink" VALUES(11,32,1,2455542.19482639); +CREATE TABLE event( + type TEXT, + mtime DATETIME, + objid INTEGER PRIMARY KEY, + tagid INTEGER, + uid INTEGER REFERENCES user, + bgcolor TEXT, + euser TEXT, + user TEXT, + ecomment TEXT, + comment TEXT, + brief TEXT, + omtime DATETIME +); +INSERT INTO "event" VALUES('ci',2455542.1246875,1,NULL,NULL,NULL,NULL,'drh',NULL,'initial empty check-in',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.12638889,5,NULL,NULL,NULL,NULL,'drh',NULL,'add three initial files',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.12795139,8,NULL,NULL,NULL,NULL,'drh',NULL,'add four.txt',NULL,2455542.12795139); +INSERT INTO "event" VALUES('ci',2455542.12873843,11,NULL,NULL,NULL,NULL,'drh',NULL,'add five.txt',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.1294213,13,NULL,NULL,NULL,NULL,'drh',NULL,'add six.txt',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.12998843,15,NULL,NULL,NULL,NULL,'drh',NULL,'changes to one.txt',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.13015046,17,NULL,NULL,NULL,NULL,'drh',NULL,'changes to two.txt',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.13335648,21,NULL,NULL,NULL,NULL,'drh',NULL,'changes to three.txt',NULL,2455542.13335648); +INSERT INTO "event" VALUES('ci',2455542.13467593,24,NULL,NULL,NULL,NULL,'drh',NULL,'drop one; add new four',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.13571759,26,NULL,NULL,NULL,NULL,'drh',NULL,'change one',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.13622685,28,NULL,NULL,NULL,NULL,'drh',NULL,'edit three; rename two',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.13659722,30,NULL,NULL,NULL,NULL,'drh',NULL,'edit two-rename',NULL,NULL); +INSERT INTO "event" VALUES('ci',2455542.19482639,32,NULL,NULL,NULL,NULL,'drh',NULL,'edit two',NULL,NULL); +CREATE TABLE phantom( + rid INTEGER PRIMARY KEY +); +CREATE TABLE orphan( + rid INTEGER PRIMARY KEY, + baseline INTEGER +); +CREATE TABLE unclustered( + rid INTEGER PRIMARY KEY +); +INSERT INTO "unclustered" VALUES(1); +INSERT INTO "unclustered" VALUES(2); +INSERT INTO "unclustered" VALUES(3); +INSERT INTO "unclustered" VALUES(4); +INSERT INTO "unclustered" VALUES(5); +INSERT INTO "unclustered" VALUES(6); +INSERT INTO "unclustered" VALUES(7); +INSERT INTO "unclustered" VALUES(8); +INSERT INTO "unclustered" VALUES(9); +INSERT INTO "unclustered" VALUES(10); +INSERT INTO "unclustered" VALUES(11); +INSERT INTO "unclustered" VALUES(12); +INSERT INTO "unclustered" VALUES(13); +INSERT INTO "unclustered" VALUES(14); +INSERT INTO "unclustered" VALUES(15); +INSERT INTO "unclustered" VALUES(16); +INSERT INTO "unclustered" VALUES(17); +INSERT INTO "unclustered" VALUES(18); +INSERT INTO "unclustered" VALUES(19); +INSERT INTO "unclustered" VALUES(20); +INSERT INTO "unclustered" VALUES(21); +INSERT INTO "unclustered" VALUES(22); +INSERT INTO "unclustered" VALUES(23); +INSERT INTO "unclustered" VALUES(24); +INSERT INTO "unclustered" VALUES(25); +INSERT INTO "unclustered" VALUES(26); +INSERT INTO "unclustered" VALUES(27); +INSERT INTO "unclustered" VALUES(28); +INSERT INTO "unclustered" VALUES(29); +INSERT INTO "unclustered" VALUES(30); +INSERT INTO "unclustered" VALUES(31); +INSERT INTO "unclustered" VALUES(32); +CREATE TABLE unsent( + rid INTEGER PRIMARY KEY +); +INSERT INTO "unsent" VALUES(31); +INSERT INTO "unsent" VALUES(32); +CREATE TABLE tag( + tagid INTEGER PRIMARY KEY, + tagname TEXT UNIQUE +); +INSERT INTO "tag" VALUES(1,'bgcolor'); +INSERT INTO "tag" VALUES(2,'comment'); +INSERT INTO "tag" VALUES(3,'user'); +INSERT INTO "tag" VALUES(4,'date'); +INSERT INTO "tag" VALUES(5,'hidden'); +INSERT INTO "tag" VALUES(6,'private'); +INSERT INTO "tag" VALUES(7,'cluster'); +INSERT INTO "tag" VALUES(8,'branch'); +INSERT INTO "tag" VALUES(9,'closed'); +INSERT INTO "tag" VALUES(10,'sym-trunk'); +INSERT INTO "tag" VALUES(11,'sym-baseline'); +INSERT INTO "tag" VALUES(12,'sym-br1'); +INSERT INTO "tag" VALUES(13,'sym-br2'); +INSERT INTO "tag" VALUES(14,'sym-br3'); +INSERT INTO "tag" VALUES(15,'sym-chng1'); +INSERT INTO "tag" VALUES(16,'sym-chng2'); +INSERT INTO "tag" VALUES(17,'sym-chng3'); +INSERT INTO "tag" VALUES(18,'sym-br4'); +INSERT INTO "tag" VALUES(19,'sym-br5'); +CREATE TABLE tagxref( + tagid INTEGER REFERENCES tag, + tagtype INTEGER, + srcid INTEGER REFERENCES blob, + origid INTEGER REFERENCES blob, + value TEXT, + mtime TIMESTAMP, + rid INTEGER REFERENCE blob, + UNIQUE(rid, tagid) +); +INSERT INTO "tagxref" VALUES(8,2,1,1,'trunk',2455542.1246875,1); +INSERT INTO "tagxref" VALUES(10,2,1,1,NULL,2455542.1246875,1); +INSERT INTO "tagxref" VALUES(4,1,6,5,'2010-12-11 15:02:00',2455542.12704861,5); +INSERT INTO "tagxref" VALUES(11,1,6,5,NULL,2455542.12704861,5); +INSERT INTO "tagxref" VALUES(8,2,0,1,'trunk',2455542.1246875,5); +INSERT INTO "tagxref" VALUES(10,2,0,1,NULL,2455542.1246875,5); +INSERT INTO "tagxref" VALUES(8,2,9,8,'br1',2455542.1281713,8); +INSERT INTO "tagxref" VALUES(12,2,9,8,NULL,2455542.1281713,8); +INSERT INTO "tagxref" VALUES(4,1,9,8,'2010-12-11 15:04:15',2455542.1281713,8); +INSERT INTO "tagxref" VALUES(10,0,9,8,NULL,2455542.1281713,8); +INSERT INTO "tagxref" VALUES(8,2,11,11,'br2',2455542.12873843,11); +INSERT INTO "tagxref" VALUES(13,2,11,11,NULL,2455542.12873843,11); +INSERT INTO "tagxref" VALUES(11,0,11,11,NULL,2455542.12873843,11); +INSERT INTO "tagxref" VALUES(10,0,11,11,NULL,2455542.12873843,11); +INSERT INTO "tagxref" VALUES(8,2,13,13,'br3',2455542.1294213,13); +INSERT INTO "tagxref" VALUES(14,2,13,13,NULL,2455542.1294213,13); +INSERT INTO "tagxref" VALUES(11,0,13,13,NULL,2455542.1294213,13); +INSERT INTO "tagxref" VALUES(10,0,13,13,NULL,2455542.1294213,13); +INSERT INTO "tagxref" VALUES(4,1,18,15,'2010-12-11 15:07:11',2455542.13072917,15); +INSERT INTO "tagxref" VALUES(15,1,18,15,NULL,2455542.13072917,15); +INSERT INTO "tagxref" VALUES(4,1,19,17,'2010-12-11 15:07:25',2455542.13090278,17); +INSERT INTO "tagxref" VALUES(16,1,19,17,NULL,2455542.13090278,17); +INSERT INTO "tagxref" VALUES(8,2,0,1,'trunk',2455542.1246875,15); +INSERT INTO "tagxref" VALUES(8,2,0,1,'trunk',2455542.1246875,17); +INSERT INTO "tagxref" VALUES(8,2,0,1,'trunk',2455542.1246875,21); +INSERT INTO "tagxref" VALUES(10,2,0,1,NULL,2455542.1246875,15); +INSERT INTO "tagxref" VALUES(10,2,0,1,NULL,2455542.1246875,17); +INSERT INTO "tagxref" VALUES(10,2,0,1,NULL,2455542.1246875,21); +INSERT INTO "tagxref" VALUES(4,1,22,21,'2010-12-11 15:12:02',2455542.13353009,21); +INSERT INTO "tagxref" VALUES(17,1,22,21,NULL,2455542.13353009,21); +INSERT INTO "tagxref" VALUES(8,2,24,24,'br4',2455542.13467593,24); +INSERT INTO "tagxref" VALUES(18,2,24,24,NULL,2455542.13467593,24); +INSERT INTO "tagxref" VALUES(11,0,24,24,NULL,2455542.13467593,24); +INSERT INTO "tagxref" VALUES(10,0,24,24,NULL,2455542.13467593,24); +INSERT INTO "tagxref" VALUES(8,2,26,26,'br5',2455542.13571759,26); +INSERT INTO "tagxref" VALUES(19,2,26,26,NULL,2455542.13571759,26); +INSERT INTO "tagxref" VALUES(11,0,26,26,NULL,2455542.13571759,26); +INSERT INTO "tagxref" VALUES(10,0,26,26,NULL,2455542.13571759,26); +INSERT INTO "tagxref" VALUES(8,2,0,26,'br5',2455542.13571759,28); +INSERT INTO "tagxref" VALUES(8,2,0,26,'br5',2455542.13571759,30); +INSERT INTO "tagxref" VALUES(19,2,0,26,NULL,2455542.13571759,28); +INSERT INTO "tagxref" VALUES(19,2,0,26,NULL,2455542.13571759,30); +INSERT INTO "tagxref" VALUES(8,2,0,11,'br2',2455542.12873843,32); +INSERT INTO "tagxref" VALUES(13,2,0,11,NULL,2455542.12873843,32); +CREATE TABLE backlink( + target TEXT, + srctype INT, + srcid INT, + mtime TIMESTAMP, + UNIQUE(target, srctype, srcid) +); +CREATE TABLE attachment( + attachid INTEGER PRIMARY KEY, + isLatest BOOLEAN DEFAULT 0, + mtime TIMESTAMP, + src TEXT, + target TEXT, + filename TEXT, + comment TEXT, + user TEXT +); +CREATE TABLE ticket( + -- Do not change any column that begins with tkt_ + tkt_id INTEGER PRIMARY KEY, + tkt_uuid TEXT UNIQUE, + tkt_mtime DATE, + -- Add as many field as required below this line + type TEXT, + status TEXT, + subsystem TEXT, + priority TEXT, + severity TEXT, + foundin TEXT, + private_contact TEXT, + resolution TEXT, + title TEXT, + comment TEXT +); +CREATE INDEX delta_i1 ON delta(srcid); +CREATE INDEX mlink_i1 ON mlink(mid); +CREATE INDEX mlink_i2 ON mlink(fnid); +CREATE INDEX mlink_i3 ON mlink(fid); +CREATE INDEX mlink_i4 ON mlink(pid); +CREATE INDEX plink_i2 ON plink(cid,pid); +CREATE INDEX event_i1 ON event(mtime); +CREATE INDEX orphan_baseline ON orphan(baseline); +CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); +CREATE INDEX backlink_src ON backlink(srcid, srctype); +CREATE INDEX attachment_idx1 ON attachment(target, filename, mtime); +CREATE INDEX attachment_idx2 ON attachment(src); +COMMIT; diff --git a/test/merge6.test b/test/merge6.test new file mode 100644 index 0000000..a9d0326 --- /dev/null +++ b/test/merge6.test @@ -0,0 +1,71 @@ +# +# Copyright (c) 2014 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests of the "merge" command +# + +#################################################################### +# TEST 1: Handle multiple merges each with one or more ADDED files # +#################################################################### + +test_setup +fossil ls + +test merge_multi-0 {[normalize_result] eq {}} + +write_file f1 "f1 line" +fossil add f1 +fossil commit -m "base file" +fossil ls + +test merge_multi-1 {[normalize_result] eq {f1}} + +fossil update trunk +write_file f2 "f2 line" +fossil add f2 +fossil commit -m "branch for file f2" -b branch_for_f2 +fossil ls + +test merge_multi-2 {[normalize_result] eq {f1 +f2}} + +fossil update trunk +write_file f3 "f3 line" +write_file f4 "f4 line" +fossil add f3 +fossil add f4 +fossil commit -m "branch for files f3 and f4" -b branch_for_f3_f4 +fossil ls + +test merge_multi-3 {[normalize_result] eq {f1 +f3 +f4}} + +fossil update trunk +fossil merge branch_for_f2 +fossil merge branch_for_f3_f4 +fossil commit -m "new trunk files f2, f3, and f4 via merge" +fossil ls + +test merge_multi-4 {[normalize_result] eq {f1 +f2 +f3 +f4}} + +############################################################################### + +test_cleanup diff --git a/test/merge_exe.test b/test/merge_exe.test new file mode 100644 index 0000000..c0ffc5e --- /dev/null +++ b/test/merge_exe.test @@ -0,0 +1,93 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Testing changes to a file's execute bit caused by a merge +# + +if {$tcl_platform(platform) eq "unix"} { + proc setx {fn isexe} { + file attributes $fn -permissions [expr {$isexe ? "+" : "-"}]x + } + + proc test_exe {fn expected} { + test merge_exe-$fn {[file executable $fn]==$expected} + } +} else { + # WARNING: This is a hack for setting and testing a file's execute bit + # on Windows. Never operate directly on Fossil database files like this + # unless you really need to and really know what you're doing. + + proc query {sql} { + return [exec $::fossilexe sqlite3 --no-repository _FOSSIL_ $sql] + } + + proc setx {fn isexe} { + set isexe [expr {bool($isexe)}] + query "UPDATE vfile SET isexe=$isexe WHERE pathname='$fn'" + } + + proc test_exe {fn expected} { + set result [query "SELECT isexe FROM vfile WHERE pathname='$fn'"] + test merge_exe-$fn {$result==$expected} + } +} + +test_setup + +write_file f1 "line" +write_file f2 "line" +write_file f3 "line" +write_file f4 "line" +fossil addremove +setx f3 1 +setx f4 1 +fossil commit -m "add files" + +write_file f0 "f0" +fossil add f0 +setx f0 1 +fossil mv --hard f1 f1n +setx f1n 1 +write_file f2 "line\nline2" +setx f2 1 +write_file f3 "line\nline2" +setx f3 0 +setx f4 0 +fossil commit -b b -m "changes" + +fossil update trunk +write_file f3 "line3\nline" +fossil commit -m "edit f3" + +fossil merge b +test_status_list merge_exe-mrg $RESULT { + EXECUTABLE f1 + EXECUTABLE f2 + UNEXEC f3 + UNEXEC f4 + UPDATE f2 + MERGE f3 + RENAME f1 -> f1n + ADDED f0 +} +foreach {fn isexe} {f0 1 f1n 1 f2 1 f3 0 f4 0} { + test_exe $fn $isexe +} + +############################################################################### + +test_cleanup diff --git a/test/merge_renames.test b/test/merge_renames.test new file mode 100644 index 0000000..76499f1 --- /dev/null +++ b/test/merge_renames.test @@ -0,0 +1,559 @@ +# +# Tests for merging with renames +# +# + +proc commit_id {version} { + regexp -line {^artifact:\s+(\S+)} [fossil whatis $version] - id + return $id +} + +require_no_open_checkout + +###################################### +# Test 1 # +# Reported: Ticket [554f44ee74e3d] # +###################################### + +test_setup + +write_file f1 "line" +fossil add f1 +fossil commit -m "c1" +fossil tag add pivot current + +write_file f1 "line2" +fossil commit -m "c2" + +write_file f1 "line3" +fossil commit -m "c3" + +write_file f1 "line4" +fossil commit -m "c4" + +write_file f1 "line5" +fossil commit -m "c4" + +write_file f1 "line6" +fossil commit -m "c4" + +fossil update pivot +fossil mv --hard f1 f2 +fossil commit -b rename -m "c5" + +fossil merge trunk +fossil commit -m "trunk merged" + +fossil update pivot +write_file f3 "someline" +fossil add f3 +fossil commit -b branch2 -m "newbranch" + +fossil merge trunk +test_status_list merge_renames-1 $RESULT {UPDATE f1} + +###################################### +# Test 2 # +# Reported: Ticket [74413366fe5067] # +###################################### + +test_setup + +write_file f1 "line" +fossil add f1 +fossil commit -m "base file" +fossil tag add pivot current + +write_file f2 "line2" +fossil add f2 +fossil commit -m "newfile" + +fossil mv --hard f2 f2new +fossil commit -m "rename" + +fossil update pivot +write_file f1 "line3" +fossil commit -b branch -m "change" + +fossil merge trunk +fossil commit -m "trunk merged" + +fossil update trunk + +fossil merge branch +test_status_list merge_renames-2 $RESULT {UPDATE f1} + +###################################### +# Test 3 # +# Reported: Ticket [30b28cf351] # +###################################### + +test_setup + +write_file f1 "line" +fossil add f1 +fossil commit -m "base file" +fossil tag add pivot current + +write_file f2 "line2" +fossil add f2 +fossil commit -m "newfile" + +fossil mv --hard f2 f2new +fossil commit -m "rename" + +fossil update pivot +write_file f1 "line3" +fossil commit -b branch -m "change" + +fossil merge trunk +fossil commit -m "trunk merged" + +fossil update trunk + +fossil merge branch +test_status_list merge_renames-3 $RESULT {UPDATE f1} + +###################################### +# Test 4 # +# Reported: Ticket [67176c3aa4] # +###################################### + +test_setup + +write_file f1 "f1" +fossil add f1 +fossil commit -m "add f1" + +write_file f1 "f1.1" +fossil commit --branch b -m "change f1" + +fossil update trunk +fossil mv --hard f1 f2 +fossil commit -m "f1 -> f2" + +fossil merge b +test_status_list merge_renames-4-1 $RESULT {UPDATE f2} +test_file_contents merge_renames-4-2 f2 "f1.1" + +###################################### +# Test 5 # +# Handle Rename/Add via Merge # +###################################### + +test_setup + +write_file f1 "old f1 line" +fossil add f1 +fossil commit -m "base file" + +write_file f3 "f3 line" +fossil add f3 +fossil commit -m "branch file" -b branch_for_f3 + +fossil update trunk +fossil mv --hard f1 f2 +write_file f1 "new f1 line" +fossil add f1 +fossil commit -m "rename and add file with old name" + +fossil update branch_for_f3 +fossil merge trunk +test_status_list merge_renames-5-1 $RESULT { + RENAME f1 -> f2 + ADDED f1 +} + +fossil commit -m "trunk merged, should have 3 files" + +fossil ls + +test merge_renames-5-2 {[normalize_result] eq {f1 +f2 +f3}} + +##################################### +# Test 6 # +# Merging a branch multiple times # +##################################### + +test_setup + +write_file f1 "f1" +fossil add f1 +fossil commit -m "add f1" + +fossil mv --hard f1 f2 +fossil commit -b b -m "f1 -> f2" + +fossil update trunk +write_file f3 "f3" +write_file f4 "f4" +fossil add f3 f4 +fossil ci -m "add f3, f4" + +fossil mv --hard f3 f3-old +fossil mv --hard f4 f3 +fossil mv --hard f3-old f4 +fossil ci -m "swap f3 and f4" + +write_file f1 "f1.1" +fossil commit -m "edit f1" + +fossil update b +fossil merge trunk +fossil commit -m "merge trunk" + +fossil update trunk +write_file f1 "f1.2" +write_file f3 "f3.1" +write_file f4 "f4.1" +fossil commit -m "edit f1, f4" + +fossil update b +fossil merge trunk +test_status_list merge_renames-6-1 $RESULT { + UPDATE f2 + UPDATE f3 + UPDATE f4 +} +test_file_contents merge_renames-6-2 f2 "f1.2" +test_file_contents merge_renames-6-3 f3 "f3.1" +test_file_contents merge_renames-6-4 f4 "f4.1" + +######################################################################## +# Test 7 # +# Merging with an uncommitted rename of a file that has been renamed # +# in the merged branch and adding a new file with the original name # +######################################################################## + +test_setup + +write_file f1 "f1" +fossil add f1 +fossil commit -m "add f1" + +fossil mv --hard f1 f2 +write_file f2 "f2" +fossil commit -b b -m "f1 -> f2, edit f2" + +fossil update trunk +fossil mv --hard f1 f3 +write_file f1 "f1.1" +fossil add f1 +fossil merge b +test_status_list merge_renames-7-1 $RESULT {UPDATE f3} +test_file_contents merge_renames-7-2 f1 "f1.1" +test_file_contents merge_renames-7-3 f3 "f2" + +###################################################### +# Test 8 # +# Merging two branches that both add the same file # +###################################################### + +test_setup + +write_file f1 "f1.1" +fossil add f1 +fossil commit -b b1 -m "add f1" + +fossil update trunk +write_file f1 "f1.2" +fossil add f1 +fossil commit -b b2 -m "add f1" + +fossil update trunk +fossil merge b1 +fossil merge b2 -expectError +test_status_list merge_renames-8-1 $RESULT { + MERGE f1 + WARNING: 1 merge conflicts +} + +fossil revert +fossil merge --integrate b1 +fossil merge b2 -expectError +test_status_list merge_renames-8-2 $RESULT { + MERGE f1 + WARNING: 1 merge conflicts +} + +############################################# +# Test 9 # +# Merging a delete/rename/add combination # +############################################# + +test_setup + +write_file f1 "f1" +write_file f2 "f2" +fossil add f1 f2 +fossil commit -m "add files" + +fossil rm --hard f2 +fossil commit -b b -m "delete f2" + +fossil mv --hard f1 f2 +fossil commit -m "f1 -> f2" + +write_file f1 "f1.1" +fossil add f1 +fossil commit -m "add new f1" + +fossil update trunk +fossil merge b +set expectedMerge { + DELETE f2 + RENAME f1 -> f2 + ADDED f1 +} +test_status_list merge_renames-9-1 $RESULT $expectedMerge +fossil changes +test_status_list merge_renames-9-2 $RESULT " + MERGED_WITH [commit_id b] + ADDED_BY_MERGE f1 + RENAMED f1 -> f2 + DELETED f2 -> f2 (overwritten by rename) +" +test_file_contents merge_renames-9-3 f1 "f1.1" +test_file_contents merge_renames-9-4 f2 "f1" + +# Undo and ensure a dry run merge results in no changes +fossil undo +test_status_list merge_renames-9-5 $RESULT { + UNDO f1 + UNDO f2 +} +fossil merge -n b -expectError +test_status_list merge_renames-9-6 $RESULT " + $expectedMerge + REMINDER: this was a dry run - no files were actually changed. +" +test merge_renames-9-7 {[fossil changes] eq ""} + +################################################################### +# Test 10 # +# Merge swapped filenames, backout the swap, then merge changes # +################################################################### + +test_setup + +write_file f1 "f1" +write_file f2 "f2" +fossil add f1 f2 +fossil commit -m "add files" ;# N + +fossil mv --hard f1 f1-tmp +fossil mv --hard f2 f1 +fossil mv --hard f1-tmp f2 +fossil commit -b b -m "swap f1, f2" ;# P + +fossil update trunk +fossil merge b +test_status_list merge_renames-10-1 $RESULT { + RENAME f1 -> f2 + RENAME f2 -> f1 +} +test_file_contents merge_renames-10-2 f1 "f2" +test_file_contents merge_renames-10-3 f2 "f1" +fossil commit -m "merge b" + +fossil update b +write_file f1 f1.1 +write_file f2 f2.1 +fossil commit -m "edit" ;# M + +fossil update trunk +fossil merge --backout trunk +test_status_list merge_renames-10-4 $RESULT { + RENAME f1 -> f2 + RENAME f2 -> f1 +} +test_file_contents merge_renames-10-5 f1 "f1" +test_file_contents merge_renames-10-6 f2 "f2" +test_status_list merge_renames-10-7 [fossil changes] " + RENAMED f1 -> f2 + RENAMED f2 -> f1 + BACKOUT [commit_id trunk] +" +fossil commit -m "swap back" ;# V + +fossil merge b +test_status_list merge_renames-10-8 $RESULT { + UPDATE f1 + UPDATE f2 +} + +test_file_contents merge_renames-10-9 f1 "f2.1" +test_file_contents merge_renames-10-10 f2 "f1.1" + +############################################ +# Test 11 # +# Specifying a baseline # +############################################ + +test_setup + +write_file f1 "line" +fossil add f1 +fossil commit -m "add f1" + +write_file f1 "line\nline2" +fossil commit -b b -m "edit f2" --tag p1 + +fossil mv --hard f1 f2 +fossil commit -m "f1 -> f2" + +write_file f2 "line\nline2\nline3" +fossil commit -m "edit f2" --tag p2 + +write_file f2 "line\nline2\nline3\nline4" +fossil commit -m "edit f2" + +fossil update trunk +fossil merge --baseline p1 b +test_status_list merge_renames-11-1 $RESULT { + MERGE f1 + RENAME f1 -> f2 +} +test_file_contents merge_renames-11-2 f2 "line\nline3\nline4" +fossil revert +fossil merge --baseline p2 b +test_status_list merge_renames-11-3 $RESULT {MERGE f1} +test_file_contents merge_renames-11-4 f1 "line\nline4" + +################################################################# +# Test 12 # +# Merge involving a pivot that isn't a first-parent ancestor # +# of either the checked-out commit or the commit being merged # +################################################################# + +test_setup + +write_file f1 "f1\n" +fossil add f1 +fossil commit -m "add f1" --tag n + +fossil mv --hard f1 f1n +fossil commit -m "f1 -> f1n" + +fossil mv --hard f1n f1v +write_file f1v "f1v\n" +fossil commit -b v -m "f1n -> f1v, edit f1v" + +fossil update trunk +fossil mv --hard f1n f1m +fossil commit -b m -m "f1n -> f1m" + +fossil update n +fossil mv --hard f1 f1p +write_file f1p "f1\np" +fossil commit -b p -m "f1 -> f1p, edit f1p" + +fossil update m +fossil merge p +test_status_list merge_renames-12-1 $RESULT {UPDATE f1m} +test_file_contents merge_renames-12-2 f1m "f1\np" +fossil commit -m "merge p" + +write_file f1m "f1\nm" +fossil commit -m "edit f1m" + +fossil update v +fossil merge p +test_status_list merge_renames-12-3 $RESULT {MERGE f1v} +test_file_contents merge_renames-12-4 f1v "f1v\np" +fossil commit -m "merge p" + +fossil merge m +test_status_list merge_renames-12-5 $RESULT {MERGE f1v} +test_file_contents merge_renames-12-6 f1v "f1v\nm" +fossil commit -m "merge m" + +################################################################# +# Test 13 # +# Merge in add+rename that happened on a branch, then merged # +# back to branch, and again to trunk, then merge in branch. # +################################################################# + +set repoDir [test_setup] +write_file f1 "line1" +fossil add f1 +fossil commit -m "add f1" --tag c1 + +write_file f2 "line1" +fossil add f2 +fossil commit -m "add f2 on branch" -b b --tag c2 +fossil update trunk +test_status_list merge_renames_13-1 $RESULT {REMOVE f2} +write_file f1 "line1\nline2\n" +fossil commit -m "edit f1 on trunk" --tag c3 + +fossil update b +test_status_list merge_renames_13-2 $RESULT { + UPDATE f1 + ADD f2 +} +fossil merge trunk +fossil commit -m "merge trunk" --tag c4 +fossil mv --hard f2 f2n +test_status_list merge_renames-13-3 $RESULT " + RENAME f2 f2n + MOVED_FILE [file normalize $repoDir]/f2 +" +fossil commit -m "renamed f2->f2n" --tag c5 + +fossil update trunk +fossil merge b +test_status_list merge_renames-13-4 $RESULT {ADDED f2n} +fossil commit -m "merge f2n" --tag m1 --tag c6 + +fossil update b +write_file f1 "line1\nline3\nline2" +fossil commit -m "edit f1 on b" --tag c7 + +fossil update trunk +write_file f1 "line1\nline3\nline2\nline4" +fossil commit -m "edit f1 on trunk" --tag c8 + +fossil update b +fossil merge trunk +test_status_list merge_renames-13-5 $RESULT {MERGE f1} +fossil commit -m "merge trunk" --tag c9 +write_file f1 "line1\nline3\nline4" +fossil commit -m "edit f1 on b" --tag c10 + +fossil update m1 +fossil merge b +test_status_list merge_renames-13-6 $RESULT { + UPDATE f1 +} +test_file_contents merge_renames-13-7 f2n "line1" + +fossil revert +test_status_list merge_renames-13-8 $RESULT { + REVERT f1 +} +fossil update trunk +fossil merge --integrate b +test_status_list merge_renames-13-9 $RESULT { + UPDATE f1 +} +test_file_contents merge_renames-13-10 f2n "line1" + +fossil revert +test_status_list merge_renames-13-11 $RESULT { + REVERT f1 +} + +###################################### +# +# Tests for troubles not specifically linked with renames but that I'd like to +# write: +# [c26c63eb1b] - 'merge --backout' does not handle conflicts properly +# [953031915f] - Lack of warning when overwriting extra files +# [4df5f38f1e] - Troubles merging a file delete with a file change + +############################################################################### + +test_cleanup diff --git a/test/merge_renames_2.test b/test/merge_renames_2.test new file mode 100644 index 0000000..5b13089 --- /dev/null +++ b/test/merge_renames_2.test @@ -0,0 +1,59 @@ +# +# Tests for merging with renames +# +# + +proc commit_id {version} { + regexp -line {^artifact:\s+(\S+)} [fossil whatis $version] - id + return $id +} + +require_no_open_checkout + +################################################################# +# Test 1 # +# https://fossil-scm.org/forum/forumpost/549700437b # +################################################################# + +test_setup + +write_file file1 "file1\n" +fossil add file1 +fossil commit -m "added file1" + +write_file file2 "file2\n" +fossil add file2 +fossil commit -m "added file2" --branch added + +write_file file2 "edit file2 on added\n" +fossil commit -m "edited file2" + +fossil mv --hard file2 file2.renamed +fossil commit -m "renamed file2" --branch renamed + +fossil branch new branched current + +write_file file2.renamed "edit file2.renamed on renamed\n" +fossil commit -m "edited file2.renamed" + +fossil update trunk +fossil merge renamed +fossil commit -m "merged from renamed" + +write_file file2.renamed "edit file2.renamed on trunk (1)\n" +fossil commit -m "edited file2.renamed on trunk (1)" + +fossil update branched +fossil merge trunk +test_status_list merge_renames_2-1.1 $RESULT {UPDATE file2.renamed} +fossil commit -m "merged edit from trunk (1:this merge succeeded)" + +fossil update trunk +write_file file2.renamed "edit2 file2.renamed on trunk (2)\n" +fossil commit -m "edited file2.renamed on trunk (2)" + +fossil update branched +fossil merge trunk +test_status_list merge_renames_2-1.2 $RESULT {UPDATE file2.renamed} + +test_cleanup diff --git a/test/merge_warn.test b/test/merge_warn.test new file mode 100644 index 0000000..3bd1b7f --- /dev/null +++ b/test/merge_warn.test @@ -0,0 +1,60 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Testing "merge" command warnings +# + +test_setup + +write_file f1 "f1" +fossil add f1 +fossil commit -m "add f1" --tag pivot + +write_file f2 "f2" +fossil add f2 +fossil commit -m "add f2" + +fossil update pivot +fossil rm --hard f1 +write_file f2 "f2.1" +write_file f3 "f3" +fossil add f2 f3 +fossil commit -b b -m "delete f1, add f2 and f3" --tag mrg + +write_file f4 "f4" +fossil add f4 +fossil commit -m "add f4" + +fossil update trunk +write_file f1 "f1.1" +write_file f3 "f3.1" +fossil merge --integrate mrg -expectError +test_status_list merge_warn-1 $RESULT { + WARNING: 1 unmanaged files were overwritten + WARNING: 2 merge conflicts + DELETE f1 + MERGE f2 + ADDED f3 (overwrites an unmanaged file), original copy backed up locally + WARNING: local edits lost for f1 +} +test merge_warn-2 { + [string first "ignoring --integrate: mrg is not a leaf" $RESULT]>=0 +} + +############################################################################### + +test_cleanup diff --git a/test/mv-rm.test b/test/mv-rm.test new file mode 100644 index 0000000..8f318a6 --- /dev/null +++ b/test/mv-rm.test @@ -0,0 +1,470 @@ +# +# Copyright (c) 2011 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# MV / RM Commands +# + +set path [file dirname [info script]] + +require_no_open_checkout + +######################################## +# Setup: Add Files and Commit # +######################################## + +test_setup; set rootDir [file normalize [pwd]] + +set undoMsg "\n \"fossil undo\" is\ +available to undo changes to the\ +working checkout." + +write_file f1 "f1" +write_file f2 "f2" +write_file f3 "f3" +write_file f4 "f4" +write_file f5 "f5" +write_file f6 "f6" +write_file f7 "f7" +write_file f8 "f8" + +file mkdir [file join $rootDir subdirA] +# NOTE: There are no files in subdirA. + +file mkdir [file join $rootDir subdirB] +write_file [file join $rootDir subdirB f9] "f9" + +file mkdir [file join $rootDir subdirC] +write_file [file join $rootDir subdirC f10] "f10" +write_file [file join $rootDir subdirC f11] "f11" +write_file f12 "f12" + +file mkdir [file join $rootDir subdirE a] +write_file [file join $rootDir subdirE a f14] "f14" + +fossil add f1 f2 f3 f4 f5 f6 f7 f8 subdirB/f9 subdirC/f10 subdirC/f11 f12 +fossil add subdirE/a/f14 +fossil commit -m "c1" + +######################################## +# Test 1: Soft Move Relative Directory # +######################################## + +file mkdir [file join $rootDir subdir1] +cd [file join $rootDir subdir1] + +fossil mv ../f1 . +test mv-soft-relative-1 {$RESULT eq "RENAME f1 subdir1/f1"} + +fossil revert +test mv-soft-relative-2 { + [normalize_result] eq "DELETE subdir1/f1\nREVERT f1${undoMsg}" +} + +cd $rootDir + +################################### +# Test 2: Soft Move Relative File # +################################### + +file mkdir [file join $rootDir subdir2] +cd [file join $rootDir subdir2] + +fossil mv ../f2 ./f2 +test mv-soft-relative-3 {$RESULT eq "RENAME f2 subdir2/f2"} + +fossil revert +test mv-soft-relative-4 { + [normalize_result] eq "DELETE subdir2/f2\nREVERT f2${undoMsg}" +} + +cd $rootDir + +######################################## +# Test 3: Hard Move Relative Directory # +######################################## + +file mkdir [file join $rootDir subdir3] +cd [file join $rootDir subdir3] + +fossil mv --hard ../f3 . +test mv-hard-relative-1 { + [normalize_result] eq "RENAME f3 subdir3/f3\nMOVED_FILE ${rootDir}/f3" +} + +fossil revert +test mv-hard-relative-2 { + [normalize_result] eq "DELETE subdir3/f3\nREVERT f3${undoMsg}" +} + +cd $rootDir + +################################### +# Test 4: Hard Move Relative File # +################################### + +file mkdir [file join $rootDir subdir4] +cd [file join $rootDir subdir4] + +fossil mv --hard ../f4 ./f4 +test mv-hard-relative-3 { + [normalize_result] eq "RENAME f4 subdir4/f4\nMOVED_FILE ${rootDir}/f4" +} + +fossil revert +test mv-hard-relative-4 { + [normalize_result] eq "DELETE subdir4/f4\nREVERT f4${undoMsg}" +} + +cd $rootDir + +######################################## +# Test 5: Soft Move Absolute Directory # +######################################## + +file mkdir [file join $rootDir subdir5] +cd [file join $rootDir subdir5] + +fossil mv [file join $rootDir f5] [file join $rootDir subdir5] +test mv-soft-absolute-1 {$RESULT eq "RENAME f5 subdir5/f5"} + +fossil revert +test mv-soft-absolute-2 { + [normalize_result] eq "DELETE subdir5/f5\nREVERT f5${undoMsg}" +} + +cd $rootDir + +################################### +# Test 6: Soft Move Absolute File # +################################### + +file mkdir [file join $rootDir subdir6] +cd [file join $rootDir subdir6] + +fossil mv [file join $rootDir f6] [file join $rootDir subdir6 f6] +test mv-soft-absolute-3 {$RESULT eq "RENAME f6 subdir6/f6"} + +fossil revert +test mv-soft-absolute-4 { + [normalize_result] eq "DELETE subdir6/f6\nREVERT f6${undoMsg}" +} + +cd $rootDir + +######################################## +# Test 7: Hard Move Absolute Directory # +######################################## + +file mkdir [file join $rootDir subdir7] +cd [file join $rootDir subdir7] + +fossil mv --hard [file join $rootDir f7] [file join $rootDir subdir7] +test mv-hard-absolute-1 { + [normalize_result] eq "RENAME f7 subdir7/f7\nMOVED_FILE ${rootDir}/f7" +} + +fossil revert +test mv-hard-absolute-2 { + [normalize_result] eq "DELETE subdir7/f7\nREVERT f7${undoMsg}" +} + +cd $rootDir + +################################### +# Test 8: Hard Move Absolute File # +################################### + +file mkdir [file join $rootDir subdir8] +cd [file join $rootDir subdir8] + +fossil mv --hard [file join $rootDir f8] [file join $rootDir subdir8 f8] +test mv-hard-absolute-3 { + [normalize_result] eq "RENAME f8 subdir8/f8\nMOVED_FILE ${rootDir}/f8" +} + +fossil revert +test mv-hard-absolute-4 { + [normalize_result] eq "DELETE subdir8/f8\nREVERT f8${undoMsg}" +} + +cd $rootDir + +########################################## +# Test 9: Soft Remove Relative Directory # +########################################## + +file mkdir [file join $rootDir subdir1] +cd [file join $rootDir subdir1] + +fossil rm ../subdirA +test rm-soft-relative-1 {$RESULT eq ""} + +fossil rm ../subdirB +test rm-soft-relative-2 {$RESULT eq "DELETED subdirB/f9"} + +fossil rm ../subdirC +test rm-soft-relative-3 { + [normalize_result] eq "DELETED subdirC/f10\nDELETED subdirC/f11" +} + +fossil revert +test rm-soft-relative-4 { + [normalize_result] eq \ + "REVERT subdirB/f9\nREVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" +} + +cd $rootDir + +###################################### +# Test 10: Soft Remove Relative File # +###################################### + +file mkdir [file join $rootDir subdir2] +cd [file join $rootDir subdir2] + +fossil rm ../f2 +test rm-soft-relative-5 {$RESULT eq "DELETED f2"} + +fossil revert +test rm-soft-relative-6 { + [normalize_result] eq "REVERT f2${undoMsg}" +} + +cd $rootDir + +########################################### +# Test 11: Hard Remove Relative Directory # +########################################### + +file mkdir [file join $rootDir subdir3] +cd [file join $rootDir subdir3] + +fossil rm --hard ../subdirA +test rm-hard-relative-1 { + [normalize_result] eq "" +} + +fossil rm --hard ../subdirB +test rm-hard-relative-2 { + [normalize_result] eq \ + "DELETED subdirB/f9\nDELETED_FILE ${rootDir}/subdirB/f9" +} + +fossil rm --hard ../subdirC +test rm-hard-relative-3 { + [normalize_result] eq \ + "DELETED subdirC/f10\nDELETED subdirC/f11\nDELETED_FILE\ +${rootDir}/subdirC/f10\nDELETED_FILE ${rootDir}/subdirC/f11" +} + +fossil revert +test rm-hard-relative-4 { + [normalize_result] eq \ + "REVERT subdirB/f9\nREVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" +} + +cd $rootDir + +###################################### +# Test 12: Hard Remove Relative File # +###################################### + +file mkdir [file join $rootDir subdir4] +cd [file join $rootDir subdir4] + +fossil rm --hard ../f4 +test rm-hard-relative-5 { + [normalize_result] eq "DELETED f4\nDELETED_FILE ${rootDir}/f4" +} + +fossil revert +test rm-hard-relative-6 { + [normalize_result] eq "REVERT f4${undoMsg}" +} + +cd $rootDir + +########################################### +# Test 13: Soft Remove Absolute Directory # +########################################### + +file mkdir [file join $rootDir subdir5] +cd [file join $rootDir subdir5] + +fossil rm [file join $rootDir subdirA] +test rm-soft-absolute-1 {$RESULT eq ""} + +fossil rm [file join $rootDir subdirB] +test rm-soft-absolute-2 {$RESULT eq "DELETED subdirB/f9"} + +fossil rm [file join $rootDir subdirC] +test rm-soft-absolute-3 { + [normalize_result] eq "DELETED subdirC/f10\nDELETED subdirC/f11" +} + +fossil revert +test rm-soft-absolute-4 { + [normalize_result] eq \ + "REVERT subdirB/f9\nREVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" +} + +cd $rootDir + +###################################### +# Test 14: Soft Remove Absolute File # +###################################### + +file mkdir [file join $rootDir subdir6] +cd [file join $rootDir subdir6] + +fossil rm [file join $rootDir f6] +test rm-soft-absolute-5 {$RESULT eq "DELETED f6"} + +fossil revert +test rm-soft-absolute-6 { + [normalize_result] eq "REVERT f6${undoMsg}" +} + +cd $rootDir + +########################################### +# Test 15: Hard Remove Absolute Directory # +########################################### + +file mkdir [file join $rootDir subdir7] +cd [file join $rootDir subdir7] + +fossil rm --hard [file join $rootDir subdirA] +test rm-hard-absolute-1 {$RESULT eq ""} + +fossil rm --hard [file join $rootDir subdirB] +test rm-hard-absolute-2 { + [normalize_result] eq \ + "DELETED subdirB/f9\nDELETED_FILE ${rootDir}/subdirB/f9" +} + +fossil rm --hard [file join $rootDir subdirC] +test rm-hard-absolute-3 { + [normalize_result] eq \ + "DELETED subdirC/f10\nDELETED subdirC/f11\nDELETED_FILE\ +${rootDir}/subdirC/f10\nDELETED_FILE ${rootDir}/subdirC/f11" +} + +fossil revert +test rm-hard-absolute-4 { + [normalize_result] eq \ + "REVERT subdirB/f9\nREVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" +} + +cd $rootDir + +###################################### +# Test 16: Hard Remove Absolute File # +###################################### + +file mkdir [file join $rootDir subdir8] +cd [file join $rootDir subdir8] + +fossil rm --hard [file join $rootDir f8] +test rm-hard-absolute-5 { + [normalize_result] eq "DELETED f8\nDELETED_FILE ${rootDir}/f8" +} + +fossil revert +test rm-hard-absolute-6 { + [normalize_result] eq "REVERT f8${undoMsg}" +} + +cd $rootDir + +####################################### +# Test 17: Move File to New Directory # +####################################### + +fossil mv --hard f12 d2/f13 +test mv-file-new-directory-1 { + [normalize_result] eq "RENAME f12 d2/f13\nMOVED_FILE ${rootDir}/f12" +} + +test mv-file-new-directory-2 {[file size d2/f13] == 3} +test mv-file-new-directory-3 {[read_file d2/f13] eq "f12"} + +fossil revert +test mv-file-new-directory-4 { + [normalize_result] eq "DELETE d2/f13\nREVERT f12${undoMsg}" +} + +test mv-file-new-directory-5 {[file size f12] == 3} +test mv-file-new-directory-6 {[read_file f12] eq "f12"} + +cd $rootDir + +############################################ +# Test 18: Move Directory to New Directory # +############################################ + +fossil mv --hard subdirC subdirD +test mv-file-new-directory-7 { + [normalize_result] eq "RENAME subdirC/f10 subdirD/f10\nRENAME subdirC/f11 subdirD/f11\nMOVED_FILE ${rootDir}/subdirC/f10\nMOVED_FILE ${rootDir}/subdirC/f11" +} + +test mv-file-new-directory-8 {[file size subdirD/f10] == 3} +test mv-file-new-directory-9 {[read_file subdirD/f10] eq "f10"} +test mv-file-new-directory-10 {[file size subdirD/f11] == 3} +test mv-file-new-directory-11 {[read_file subdirD/f11] eq "f11"} + +fossil revert +test mv-file-new-directory-12 { + [normalize_result] eq "DELETE subdirD/f10\nDELETE subdirD/f11\nREVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" +} + +test mv-file-new-directory-13 {[file size subdirC/f10] == 3} +test mv-file-new-directory-14 {[read_file subdirC/f10] eq "f10"} +test mv-file-new-directory-15 {[file size subdirC/f11] == 3} +test mv-file-new-directory-16 {[read_file subdirC/f11] eq "f11"} + +cd $rootDir + +############################################################################### +# Test 19: Follow-up Soft Rename of a Directory Already Renamed on Filesystem # +############################################################################### + +file rename [file join $rootDir subdirE/a] [file join $rootDir subdirE/a_renamed] + +fossil mv subdirE/a subdirE/a_renamed +test mv-soft-already-renamed-directory-1 { + [normalize_result] eq "RENAME subdirE/a/f14 subdirE/a_renamed/f14" +} + +test mv-soft-already-renamed-directory-2 {[file size subdirE/a_renamed/f14] == 3} +test mv-soft-already-renamed-directory-3 {[read_file subdirE/a_renamed/f14] eq "f14"} + +fossil revert +test mv-soft-already-renamed-directory-4 { + [normalize_result] eq "DELETE subdirE/a_renamed/f14\nREVERT subdirE/a/f14${undoMsg}" +} + +test mv-soft-already-renamed-directory-5 {[file size subdirE/a/f14] == 3} +test mv-soft-already-renamed-directory-6 {[read_file subdirE/a/f14] eq "f14"} + +file delete -force [file join $rootDir subdirE/a_renamed] + +cd $rootDir + +############################################################################### + +test_cleanup diff --git a/test/org.test b/test/org.test new file mode 100644 index 0000000..20a0509 --- /dev/null +++ b/test/org.test @@ -0,0 +1,64 @@ +# Native Org renderer and Org wiki integration tests for the Copland fork. + +test_setup +fossil set backoffice-disable 1 + +write_file page.org {#+TITLE: Hidden Wiki Title +#+AUTHOR: Ada +#+OPTIONS: toc:2 + +* Overview + +See [[wiki:Deployment Guide#Install][deployment]], +[[file:docs/reference.org][reference]], and [[*Details][details]]. + +** Details + +Unsafe [[javascript:alert(1)][scheme]] and +[[file:../secret.org][traversal]] remain plain text. + +#+begin_src html + +#+end_src +} + +fossil test-org-render page.org +test org-render-1 {$CODE == 0 && [regexp {class="org-document"} $RESULT]} +test org-render-2 {![regexp {