| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package modfile |
| |
| import ( |
| "bytes" |
| "fmt" |
| "strings" |
| "testing" |
| |
| "golang.org/x/mod/module" |
| ) |
| |
| var addRequireTests = []struct { |
| desc string |
| in string |
| path string |
| vers string |
| out string |
| }{ |
| { |
| `existing`, |
| ` |
| module m |
| require x.y/z v1.2.3 |
| `, |
| "x.y/z", "v1.5.6", |
| ` |
| module m |
| require x.y/z v1.5.6 |
| `, |
| }, |
| { |
| `existing2`, |
| ` |
| module m |
| require ( |
| x.y/z v1.2.3 // first |
| x.z/a v0.1.0 // first-a |
| ) |
| require x.y/z v1.4.5 // second |
| require ( |
| x.y/z v1.6.7 // third |
| x.z/a v0.2.0 // third-a |
| ) |
| `, |
| "x.y/z", "v1.8.9", |
| ` |
| module m |
| |
| require ( |
| x.y/z v1.8.9 // first |
| x.z/a v0.1.0 // first-a |
| ) |
| |
| require x.z/a v0.2.0 // third-a |
| `, |
| }, |
| { |
| `new`, |
| ` |
| module m |
| require x.y/z v1.2.3 |
| `, |
| "x.y/w", "v1.5.6", |
| ` |
| module m |
| require ( |
| x.y/z v1.2.3 |
| x.y/w v1.5.6 |
| ) |
| `, |
| }, |
| { |
| `new2`, |
| ` |
| module m |
| require x.y/z v1.2.3 |
| require x.y/q/v2 v2.3.4 |
| `, |
| "x.y/w", "v1.5.6", |
| ` |
| module m |
| require x.y/z v1.2.3 |
| require ( |
| x.y/q/v2 v2.3.4 |
| x.y/w v1.5.6 |
| ) |
| `, |
| }, |
| } |
| |
| type require struct { |
| path, vers string |
| indirect bool |
| } |
| |
| var setRequireTests = []struct { |
| desc string |
| in string |
| mods []require |
| out string |
| }{ |
| { |
| `https://golang.org/issue/45932`, |
| `module m |
| require ( |
| x.y/a v1.2.3 //indirect |
| x.y/b v1.2.3 |
| x.y/c v1.2.3 |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", false}, |
| {"x.y/c", "v1.2.3", false}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 |
| x.y/c v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `existing`, |
| `module m |
| require ( |
| x.y/b v1.2.3 |
| |
| x.y/a v1.2.3 |
| x.y/d v1.2.3 |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", false}, |
| {"x.y/c", "v1.2.3", false}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 |
| x.y/c v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `existing_indirect`, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 // |
| x.y/c v1.2.3 //c |
| x.y/d v1.2.3 // c |
| x.y/e v1.2.3 // indirect |
| x.y/f v1.2.3 //indirect |
| x.y/g v1.2.3 // indirect |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| {"x.y/b", "v1.2.3", true}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", true}, |
| {"x.y/e", "v1.2.3", true}, |
| {"x.y/f", "v1.2.3", true}, |
| {"x.y/g", "v1.2.3", true}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 // indirect |
| x.y/b v1.2.3 // indirect |
| x.y/c v1.2.3 // indirect; c |
| x.y/d v1.2.3 // indirect; c |
| x.y/e v1.2.3 // indirect |
| x.y/f v1.2.3 //indirect |
| x.y/g v1.2.3 // indirect |
| ) |
| `, |
| }, |
| { |
| `existing_multi`, |
| `module m |
| require x.y/a v1.2.3 |
| require x.y/b v1.2.3 |
| require x.y/c v1.0.0 // not v1.2.3! |
| require x.y/d v1.2.3 // comment kept |
| require x.y/e v1.2.3 // comment kept |
| require x.y/f v1.2.3 // indirect |
| require x.y/g v1.2.3 // indirect |
| `, |
| []require{ |
| {"x.y/h", "v1.2.3", false}, |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", false}, |
| {"x.y/c", "v1.2.3", false}, |
| {"x.y/d", "v1.2.3", false}, |
| {"x.y/e", "v1.2.3", true}, |
| {"x.y/f", "v1.2.3", false}, |
| {"x.y/g", "v1.2.3", false}, |
| }, |
| `module m |
| require x.y/a v1.2.3 |
| |
| require x.y/b v1.2.3 |
| |
| require x.y/c v1.2.3 // not v1.2.3! |
| |
| require x.y/d v1.2.3 // comment kept |
| |
| require x.y/e v1.2.3 // indirect; comment kept |
| |
| require x.y/f v1.2.3 |
| |
| require ( |
| x.y/g v1.2.3 |
| x.y/h v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `existing_duplicate`, |
| `module m |
| require ( |
| x.y/a v1.0.0 // zero |
| x.y/a v1.1.0 // one |
| x.y/a v1.2.3 // two |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| }, |
| `module m |
| require x.y/a v1.2.3 // indirect; zero |
| `, |
| }, |
| { |
| `existing_duplicate_multi`, |
| `module m |
| require x.y/a v1.0.0 // zero |
| require x.y/a v1.1.0 // one |
| require x.y/a v1.2.3 // two |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| }, |
| `module m |
| require x.y/a v1.2.3 // indirect; zero |
| `, |
| }, |
| } |
| |
| var setRequireSeparateIndirectTests = []struct { |
| desc string |
| in string |
| mods []require |
| out string |
| }{ |
| { |
| `https://golang.org/issue/45932`, |
| `module m |
| require ( |
| x.y/a v1.2.3 //indirect |
| x.y/b v1.2.3 |
| x.y/c v1.2.3 |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", false}, |
| {"x.y/c", "v1.2.3", false}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 |
| x.y/c v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `existing`, |
| `module m |
| require ( |
| x.y/b v1.2.3 |
| |
| x.y/a v1.2.3 |
| x.y/d v1.2.3 |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", false}, |
| {"x.y/c", "v1.2.3", false}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 |
| x.y/c v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `existing_indirect`, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 // |
| x.y/c v1.2.3 //c |
| x.y/d v1.2.3 // c |
| x.y/e v1.2.3 // indirect |
| x.y/f v1.2.3 //indirect |
| x.y/g v1.2.3 // indirect |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| {"x.y/b", "v1.2.3", true}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", true}, |
| {"x.y/e", "v1.2.3", true}, |
| {"x.y/f", "v1.2.3", true}, |
| {"x.y/g", "v1.2.3", true}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 // indirect |
| x.y/b v1.2.3 // indirect |
| x.y/c v1.2.3 // indirect; c |
| x.y/d v1.2.3 // indirect; c |
| x.y/e v1.2.3 // indirect |
| x.y/f v1.2.3 //indirect |
| x.y/g v1.2.3 // indirect |
| ) |
| `, |
| }, |
| { |
| `existing_line`, |
| `module m |
| require x.y/a v1.0.0 |
| require x.y/c v1.0.0 // indirect |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", false}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", true}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 |
| ) |
| require ( |
| x.y/c v1.2.3 // indirect |
| x.y/d v1.2.3 // indirect |
| )`, |
| }, |
| { |
| `existing_multi`, |
| `module m |
| require x.y/a v1.2.3 |
| require x.y/b v1.2.3 // demoted to indirect |
| require x.y/c v1.0.0 // not v1.2.3! |
| require x.y/d v1.2.3 // comment kept |
| require x.y/e v1.2.3 // comment kept |
| require x.y/f v1.2.3 // indirect; promoted to direct |
| // promoted to direct |
| require x.y/g v1.2.3 // indirect |
| require x.y/i v1.2.3 // indirect |
| require x.y/j v1.2.3 // indirect |
| `, |
| []require{ |
| {"x.y/h", "v1.2.3", false}, // out of alphabetical order |
| {"x.y/i", "v1.2.3", true}, |
| {"x.y/j", "v1.2.3", true}, |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", true}, |
| {"x.y/c", "v1.2.3", false}, |
| {"x.y/d", "v1.2.3", false}, |
| {"x.y/e", "v1.2.3", true}, |
| {"x.y/f", "v1.2.3", false}, |
| {"x.y/g", "v1.2.3", false}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/h v1.2.3 |
| ) |
| require x.y/b v1.2.3 // indirect; demoted to indirect |
| require x.y/c v1.2.3 // not v1.2.3! |
| require x.y/d v1.2.3 // comment kept |
| require x.y/e v1.2.3 // indirect; comment kept |
| require x.y/f v1.2.3 // promoted to direct |
| // promoted to direct |
| require x.y/g v1.2.3 |
| require x.y/i v1.2.3 // indirect |
| require x.y/j v1.2.3 // indirect |
| `, |
| }, |
| { |
| `existing_duplicate`, |
| `module m |
| require ( |
| x.y/a v1.0.0 // zero |
| x.y/a v1.1.0 // one |
| x.y/a v1.2.3 // two |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| }, |
| `module m |
| require x.y/a v1.2.3 // indirect; zero |
| `, |
| }, |
| { |
| `existing_duplicate_multi`, |
| `module m |
| require x.y/a v1.0.0 // zero |
| require x.y/a v1.1.0 // one |
| require x.y/a v1.2.3 // two |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| }, |
| `module m |
| require x.y/a v1.2.3 // indirect; zero |
| `, |
| }, |
| { |
| `existing_duplicate_mix_indirect`, |
| `module m |
| require ( |
| x.y/a v1.0.0 // zero |
| x.y/a v1.1.0 // indirect; one |
| x.y/a v1.2.3 // indirect; two |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| }, |
| `module m |
| require x.y/a v1.2.3 // indirect; zero |
| `, |
| }, |
| { |
| `existing_duplicate_mix_direct`, |
| `module m |
| require ( |
| x.y/a v1.0.0 // indirect; zero |
| x.y/a v1.1.0 // one |
| x.y/a v1.2.3 // two |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| }, |
| `module m |
| require x.y/a v1.2.3 // zero |
| `, |
| }, |
| { |
| `add_indirect_after_last_direct`, |
| `module m |
| require ( |
| x.y/a v1.0.0 // comment a preserved |
| x.y/d v1.0.0 // comment d preserved |
| ) |
| require ( |
| x.y/b v1.0.0 // comment b preserved |
| x.y/e v1.0.0 // comment e preserved |
| ) |
| go 1.17 |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", false}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", false}, |
| {"x.y/e", "v1.2.3", false}, |
| {"x.y/f", "v1.2.3", true}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 // comment a preserved |
| x.y/d v1.2.3 // comment d preserved |
| ) |
| require ( |
| x.y/b v1.2.3 // comment b preserved |
| x.y/e v1.2.3 // comment e preserved |
| ) |
| require ( |
| x.y/c v1.2.3 // indirect |
| x.y/f v1.2.3 // indirect |
| ) |
| go 1.17 |
| `, |
| }, |
| { |
| `add_direct_before_first_indirect`, |
| `module m |
| require ( |
| x.y/b v1.0.0 // indirect; comment b preserved |
| x.y/e v1.0.0 // indirect; comment d preserved |
| ) |
| require ( |
| x.y/c v1.0.0 // indirect; comment c preserved |
| x.y/f v1.0.0 // indirect; comment e preserved |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", true}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", false}, |
| {"x.y/e", "v1.2.3", true}, |
| {"x.y/f", "v1.2.3", true}, |
| }, |
| `module m |
| require ( |
| x.y/b v1.2.3 // indirect; comment b preserved |
| x.y/e v1.2.3 // indirect; comment d preserved |
| ) |
| require ( |
| x.y/c v1.2.3 // indirect; comment c preserved |
| x.y/f v1.2.3 // indirect; comment e preserved |
| ) |
| require ( |
| x.y/a v1.2.3 |
| x.y/d v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `add_indirect_after_mixed`, |
| `module m |
| require ( |
| x.y/a v1.0.0 |
| x.y/b v1.0.0 // indirect |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", true}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", false}, |
| {"x.y/e", "v1.2.3", true}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 |
| x.y/d v1.2.3 |
| ) |
| require ( |
| x.y/b v1.2.3 // indirect |
| x.y/c v1.2.3 // indirect |
| x.y/e v1.2.3 // indirect |
| ) |
| `, |
| }, |
| { |
| `preserve_block_comment_indirect_to_direct`, |
| `module m |
| // save |
| require ( |
| x.y/a v1.2.3 // indirect |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| }, |
| `module m |
| |
| // save |
| require x.y/a v1.2.3 |
| `, |
| }, |
| { |
| `preserve_block_comment_direct_to_indirect`, |
| `module m |
| // save |
| require ( |
| x.y/a v1.2.3 |
| ) |
| `, |
| []require{ |
| {"x.y/a", "v1.2.3", true}, |
| }, |
| `module m |
| |
| // save |
| require x.y/a v1.2.3 // indirect |
| `, |
| }, |
| { |
| `regroup_flat_uncommented_block`, |
| `module m |
| require ( |
| x.y/a v1.0.0 // a |
| x.y/b v1.0.0 // indirect; b |
| x.y/c v1.0.0 // indirect |
| )`, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", true}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", false}, |
| }, |
| `module m |
| require ( |
| x.y/a v1.2.3 // a |
| x.y/d v1.2.3 |
| ) |
| require ( |
| x.y/b v1.2.3 // indirect; b |
| x.y/c v1.2.3 // indirect |
| )`, |
| }, |
| { |
| `dont_regroup_flat_commented_block`, |
| `module m |
| // dont regroup |
| require ( |
| x.y/a v1.0.0 |
| x.y/b v1.0.0 // indirect |
| x.y/c v1.0.0 // indirect |
| )`, |
| []require{ |
| {"x.y/a", "v1.2.3", false}, |
| {"x.y/b", "v1.2.3", true}, |
| {"x.y/c", "v1.2.3", true}, |
| {"x.y/d", "v1.2.3", false}, |
| }, |
| `module m |
| // dont regroup |
| require ( |
| x.y/a v1.2.3 |
| x.y/b v1.2.3 // indirect |
| x.y/c v1.2.3 // indirect |
| ) |
| require x.y/d v1.2.3`, |
| }, |
| } |
| |
| var addGoTests = []struct { |
| desc string |
| in string |
| version string |
| out string |
| }{ |
| { |
| `module_only`, |
| `module m |
| `, |
| `1.14`, |
| `module m |
| go 1.14 |
| `, |
| }, |
| { |
| `module_before_require`, |
| `module m |
| require x.y/a v1.2.3 |
| `, |
| `1.14`, |
| `module m |
| go 1.14 |
| require x.y/a v1.2.3 |
| `, |
| }, |
| { |
| `require_before_module`, |
| `require x.y/a v1.2.3 |
| module example.com/inverted |
| `, |
| `1.14`, |
| `require x.y/a v1.2.3 |
| module example.com/inverted |
| go 1.14 |
| `, |
| }, |
| { |
| `require_only`, |
| `require x.y/a v1.2.3 |
| `, |
| `1.14`, |
| `require x.y/a v1.2.3 |
| go 1.14 |
| `, |
| }, |
| } |
| |
| var addExcludeTests = []struct { |
| desc string |
| in string |
| path string |
| version string |
| out string |
| }{ |
| { |
| `compatible`, |
| `module m |
| `, |
| `example.com`, |
| `v1.2.3`, |
| `module m |
| exclude example.com v1.2.3 |
| `, |
| }, |
| { |
| `gopkg.in v0`, |
| `module m |
| `, |
| `gopkg.in/foo.v0`, |
| `v0.2.3`, |
| `module m |
| exclude gopkg.in/foo.v0 v0.2.3 |
| `, |
| }, |
| { |
| `gopkg.in v1`, |
| `module m |
| `, |
| `gopkg.in/foo.v1`, |
| `v1.2.3`, |
| `module m |
| exclude gopkg.in/foo.v1 v1.2.3 |
| `, |
| }, |
| } |
| |
| var addRetractTests = []struct { |
| desc string |
| in string |
| low string |
| high string |
| rationale string |
| out string |
| }{ |
| { |
| `new_singleton`, |
| `module m |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| ``, |
| `module m |
| retract v1.2.3 |
| `, |
| }, |
| { |
| `new_interval`, |
| `module m |
| `, |
| `v1.0.0`, |
| `v1.1.0`, |
| ``, |
| `module m |
| retract [v1.0.0, v1.1.0]`, |
| }, |
| { |
| `duplicate_with_rationale`, |
| `module m |
| retract v1.2.3 |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| `bad`, |
| `module m |
| retract ( |
| v1.2.3 |
| // bad |
| v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `duplicate_multiline_rationale`, |
| `module m |
| retract [v1.2.3, v1.2.3] |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| `multi |
| line`, |
| `module m |
| retract ( |
| [v1.2.3, v1.2.3] |
| // multi |
| // line |
| v1.2.3 |
| ) |
| `, |
| }, |
| { |
| `duplicate_interval`, |
| `module m |
| retract [v1.0.0, v1.1.0] |
| `, |
| `v1.0.0`, |
| `v1.1.0`, |
| ``, |
| `module m |
| retract ( |
| [v1.0.0, v1.1.0] |
| [v1.0.0, v1.1.0] |
| ) |
| `, |
| }, |
| { |
| `duplicate_singleton`, |
| `module m |
| retract v1.2.3 |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| ``, |
| `module m |
| retract ( |
| v1.2.3 |
| v1.2.3 |
| ) |
| `, |
| }, |
| } |
| |
| var dropRetractTests = []struct { |
| desc string |
| in string |
| low string |
| high string |
| out string |
| }{ |
| { |
| `singleton_no_match`, |
| `module m |
| retract v1.2.3 |
| `, |
| `v1.0.0`, |
| `v1.0.0`, |
| `module m |
| retract v1.2.3 |
| `, |
| }, |
| { |
| `singleton_match_one`, |
| `module m |
| retract v1.2.2 |
| retract v1.2.3 |
| retract v1.2.4 |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| `module m |
| retract v1.2.2 |
| retract v1.2.4 |
| `, |
| }, |
| { |
| `singleton_match_all`, |
| `module m |
| retract v1.2.3 // first |
| retract v1.2.3 // second |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| `module m |
| `, |
| }, |
| { |
| `interval_match`, |
| `module m |
| retract [v1.2.3, v1.2.3] |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| `module m |
| `, |
| }, |
| { |
| `interval_superset_no_match`, |
| `module m |
| retract [v1.0.0, v1.1.0] |
| `, |
| `v1.0.0`, |
| `v1.2.0`, |
| `module m |
| retract [v1.0.0, v1.1.0] |
| `, |
| }, |
| { |
| `singleton_match_middle`, |
| `module m |
| retract v1.2.3 |
| `, |
| `v1.2.3`, |
| `v1.2.3`, |
| `module m |
| `, |
| }, |
| { |
| `interval_match_middle_block`, |
| `module m |
| retract ( |
| v1.0.0 |
| [v1.1.0, v1.2.0] |
| v1.3.0 |
| ) |
| `, |
| `v1.1.0`, |
| `v1.2.0`, |
| `module m |
| retract ( |
| v1.0.0 |
| v1.3.0 |
| ) |
| `, |
| }, |
| { |
| `interval_match_all`, |
| `module m |
| retract [v1.0.0, v1.1.0] |
| retract [v1.0.0, v1.1.0] |
| `, |
| `v1.0.0`, |
| `v1.1.0`, |
| `module m |
| `, |
| }, |
| } |
| |
| var retractRationaleTests = []struct { |
| desc, in, want string |
| }{ |
| { |
| `no_comment`, |
| `module m |
| retract v1.0.0`, |
| ``, |
| }, |
| { |
| `prefix_one`, |
| `module m |
| // prefix |
| retract v1.0.0 |
| `, |
| `prefix`, |
| }, |
| { |
| `prefix_multiline`, |
| `module m |
| // one |
| // |
| // two |
| // |
| // three |
| retract v1.0.0`, |
| `one |
| |
| two |
| |
| three`, |
| }, |
| { |
| `suffix`, |
| `module m |
| retract v1.0.0 // suffix |
| `, |
| `suffix`, |
| }, |
| { |
| `prefix_suffix_after`, |
| `module m |
| // prefix |
| retract v1.0.0 // suffix |
| `, |
| `prefix |
| suffix`, |
| }, |
| { |
| `block_only`, |
| `// block |
| retract ( |
| v1.0.0 |
| ) |
| `, |
| `block`, |
| }, |
| { |
| `block_and_line`, |
| `// block |
| retract ( |
| // line |
| v1.0.0 |
| ) |
| `, |
| `line`, |
| }, |
| } |
| |
| var moduleDeprecatedTests = []struct { |
| desc, in, want string |
| }{ |
| // retractRationaleTests exercises some of the same code, so these tests |
| // don't exhaustively cover comment extraction. |
| { |
| `no_comment`, |
| `module m`, |
| ``, |
| }, |
| { |
| `other_comment`, |
| `// yo |
| module m`, |
| ``, |
| }, |
| { |
| `deprecated_no_colon`, |
| `//Deprecated |
| module m`, |
| ``, |
| }, |
| { |
| `deprecated_no_space`, |
| `//Deprecated:blah |
| module m`, |
| `blah`, |
| }, |
| { |
| `deprecated_simple`, |
| `// Deprecated: blah |
| module m`, |
| `blah`, |
| }, |
| { |
| `deprecated_lowercase`, |
| `// deprecated: blah |
| module m`, |
| ``, |
| }, |
| { |
| `deprecated_multiline`, |
| `// Deprecated: one |
| // two |
| module m`, |
| "one\ntwo", |
| }, |
| { |
| `deprecated_mixed`, |
| `// some other comment |
| // Deprecated: blah |
| module m`, |
| ``, |
| }, |
| { |
| `deprecated_middle`, |
| `// module m is Deprecated: blah |
| module m`, |
| ``, |
| }, |
| { |
| `deprecated_multiple`, |
| `// Deprecated: a |
| // Deprecated: b |
| module m`, |
| "a\nDeprecated: b", |
| }, |
| { |
| `deprecated_paragraph`, |
| `// Deprecated: a |
| // b |
| // |
| // c |
| module m`, |
| "a\nb", |
| }, |
| { |
| `deprecated_paragraph_space`, |
| `// Deprecated: the next line has a space |
| // |
| // c |
| module m`, |
| "the next line has a space", |
| }, |
| { |
| `deprecated_suffix`, |
| `module m // Deprecated: blah`, |
| `blah`, |
| }, |
| { |
| `deprecated_mixed_suffix`, |
| `// some other comment |
| module m // Deprecated: blah`, |
| ``, |
| }, |
| { |
| `deprecated_mixed_suffix_paragraph`, |
| `// some other comment |
| // |
| module m // Deprecated: blah`, |
| `blah`, |
| }, |
| { |
| `deprecated_block`, |
| `// Deprecated: blah |
| module ( |
| m |
| )`, |
| `blah`, |
| }, |
| } |
| |
| var sortBlocksTests = []struct { |
| desc, in, out string |
| strict bool |
| }{ |
| { |
| `exclude_duplicates_removed`, |
| `module m |
| exclude x.y/z v1.0.0 // a |
| exclude x.y/z v1.0.0 // b |
| exclude ( |
| x.y/w v1.1.0 |
| x.y/z v1.0.0 // c |
| ) |
| `, |
| `module m |
| exclude x.y/z v1.0.0 // a |
| exclude ( |
| x.y/w v1.1.0 |
| )`, |
| true, |
| }, |
| { |
| `replace_duplicates_removed`, |
| `module m |
| replace x.y/z v1.0.0 => ./a |
| replace x.y/z v1.1.0 => ./b |
| replace ( |
| x.y/z v1.0.0 => ./c |
| ) |
| `, |
| `module m |
| replace x.y/z v1.1.0 => ./b |
| replace ( |
| x.y/z v1.0.0 => ./c |
| ) |
| `, |
| true, |
| }, |
| { |
| `retract_duplicates_not_removed`, |
| `module m |
| // block |
| retract ( |
| v1.0.0 // one |
| v1.0.0 // two |
| )`, |
| `module m |
| // block |
| retract ( |
| v1.0.0 // one |
| v1.0.0 // two |
| )`, |
| true, |
| }, |
| // Tests below this point just check sort order. |
| // Non-retract blocks are sorted lexicographically in ascending order. |
| // retract blocks are sorted using semver in descending order. |
| { |
| `sort_lexicographically`, |
| `module m |
| sort ( |
| aa |
| cc |
| bb |
| zz |
| v1.2.0 |
| v1.11.0 |
| )`, |
| `module m |
| sort ( |
| aa |
| bb |
| cc |
| v1.11.0 |
| v1.2.0 |
| zz |
| ) |
| `, |
| false, |
| }, |
| { |
| `sort_retract`, |
| `module m |
| retract ( |
| [v1.2.0, v1.3.0] |
| [v1.1.0, v1.3.0] |
| [v1.1.0, v1.2.0] |
| v1.0.0 |
| v1.1.0 |
| v1.2.0 |
| v1.3.0 |
| v1.4.0 |
| ) |
| `, |
| `module m |
| retract ( |
| v1.4.0 |
| v1.3.0 |
| [v1.2.0, v1.3.0] |
| v1.2.0 |
| [v1.1.0, v1.3.0] |
| [v1.1.0, v1.2.0] |
| v1.1.0 |
| v1.0.0 |
| ) |
| `, |
| false, |
| }, |
| } |
| |
| var addRetractValidateVersionTests = []struct { |
| desc string |
| path string |
| low, high string |
| wantErr string |
| }{ |
| { |
| `blank_version`, |
| `example.com/m`, |
| ``, |
| ``, |
| `version "" invalid: must be of the form v1.2.3`, |
| }, |
| { |
| `missing prefix`, |
| `example.com/m`, |
| `1.0.0`, |
| `1.0.0`, |
| `version "1.0.0" invalid: must be of the form v1.2.3`, |
| }, |
| { |
| `non-canonical`, |
| `example.com/m`, |
| `v1.2`, |
| `v1.2`, |
| `version "v1.2" invalid: must be of the form v1.2.3`, |
| }, |
| { |
| `invalid range`, |
| `example.com/m`, |
| `v1.2.3`, |
| `v1.3`, |
| `version "v1.3" invalid: must be of the form v1.2.3`, |
| }, |
| { |
| `mismatched major`, |
| `example.com/m/v2`, |
| `v1.0.0`, |
| `v1.0.0`, |
| `version "v1.0.0" invalid: should be v2, not v1`, |
| }, |
| { |
| `missing +incompatible`, |
| `example.com/m`, |
| `v2.0.0`, |
| `v2.0.0`, |
| `version "v2.0.0" invalid: should be v2.0.0+incompatible (or module example.com/m/v2)`, |
| }, |
| } |
| |
| var addExcludeValidateVersionTests = []struct { |
| desc string |
| path string |
| version string |
| wantErr string |
| }{ |
| { |
| `blank version`, |
| `example.com/m`, |
| ``, |
| `version "" invalid: must be of the form v1.2.3`, |
| }, |
| { |
| `missing prefix`, |
| `example.com/m`, |
| `1.0.0`, |
| `version "1.0.0" invalid: must be of the form v1.2.3`, |
| }, |
| { |
| `non-canonical`, |
| `example.com/m`, |
| `v1.2`, |
| `version "v1.2" invalid: must be of the form v1.2.3`, |
| }, |
| { |
| `mismatched major`, |
| `example.com/m/v2`, |
| `v1.2.3`, |
| `version "v1.2.3" invalid: should be v2, not v1`, |
| }, |
| { |
| `missing +incompatible`, |
| `example.com/m`, |
| `v2.3.4`, |
| `version "v2.3.4" invalid: should be v2.3.4+incompatible (or module example.com/m/v2)`, |
| }, |
| } |
| |
| var fixVersionTests = []struct { |
| desc, in, want, wantErr string |
| fix VersionFixer |
| }{ |
| { |
| desc: `require`, |
| in: `require example.com/m 1.0.0`, |
| want: `require example.com/m v1.0.0`, |
| fix: fixV, |
| }, |
| { |
| desc: `replace`, |
| in: `replace example.com/m 1.0.0 => example.com/m 1.1.0`, |
| want: `replace example.com/m v1.0.0 => example.com/m v1.1.0`, |
| fix: fixV, |
| }, |
| { |
| desc: `replace_version_in_path`, |
| in: `replace example.com/m@v1.0.0 => example.com/m@v1.1.0`, |
| wantErr: `replacement module must match format 'path version', not 'path@version'`, |
| fix: fixV, |
| }, |
| { |
| desc: `replace_version_in_later_path`, |
| in: `replace example.com/m => example.com/m@v1.1.0`, |
| wantErr: `replacement module must match format 'path version', not 'path@version'`, |
| fix: fixV, |
| }, |
| { |
| desc: `exclude`, |
| in: `exclude example.com/m 1.0.0`, |
| want: `exclude example.com/m v1.0.0`, |
| fix: fixV, |
| }, |
| { |
| desc: `retract_single`, |
| in: `module example.com/m |
| retract 1.0.0`, |
| want: `module example.com/m |
| retract v1.0.0`, |
| fix: fixV, |
| }, |
| { |
| desc: `retract_interval`, |
| in: `module example.com/m |
| retract [1.0.0, 1.1.0]`, |
| want: `module example.com/m |
| retract [v1.0.0, v1.1.0]`, |
| fix: fixV, |
| }, |
| { |
| desc: `retract_nomod`, |
| in: `retract 1.0.0`, |
| wantErr: `in:1: no module directive found, so retract cannot be used`, |
| fix: fixV, |
| }, |
| } |
| |
| func fixV(path, version string) (string, error) { |
| if path != "example.com/m" { |
| return "", fmt.Errorf("module path must be example.com/m") |
| } |
| return "v" + version, nil |
| } |
| |
| func TestAddRequire(t *testing.T) { |
| for _, tt := range addRequireTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| testEdit(t, tt.in, tt.out, true, func(f *File) error { |
| err := f.AddRequire(tt.path, tt.vers) |
| f.Cleanup() |
| return err |
| }) |
| }) |
| } |
| } |
| |
| func TestSetRequire(t *testing.T) { |
| for _, tt := range setRequireTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| var mods []*Require |
| for _, mod := range tt.mods { |
| mods = append(mods, &Require{ |
| Mod: module.Version{ |
| Path: mod.path, |
| Version: mod.vers, |
| }, |
| Indirect: mod.indirect, |
| }) |
| } |
| |
| f := testEdit(t, tt.in, tt.out, true, func(f *File) error { |
| f.SetRequire(mods) |
| f.Cleanup() |
| return nil |
| }) |
| |
| if len(f.Require) != len(mods) { |
| t.Errorf("after Cleanup, len(Require) = %v; want %v", len(f.Require), len(mods)) |
| } |
| }) |
| } |
| } |
| |
| func TestSetRequireSeparateIndirect(t *testing.T) { |
| for _, tt := range setRequireSeparateIndirectTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| var mods []*Require |
| for _, mod := range tt.mods { |
| mods = append(mods, &Require{ |
| Mod: module.Version{ |
| Path: mod.path, |
| Version: mod.vers, |
| }, |
| Indirect: mod.indirect, |
| }) |
| } |
| |
| f := testEdit(t, tt.in, tt.out, true, func(f *File) error { |
| f.SetRequireSeparateIndirect(mods) |
| f.Cleanup() |
| return nil |
| }) |
| |
| if len(f.Require) != len(mods) { |
| t.Errorf("after Cleanup, len(Require) = %v; want %v", len(f.Require), len(mods)) |
| } |
| }) |
| } |
| } |
| |
| func TestAddGo(t *testing.T) { |
| for _, tt := range addGoTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| testEdit(t, tt.in, tt.out, true, func(f *File) error { |
| return f.AddGoStmt(tt.version) |
| }) |
| }) |
| } |
| } |
| |
| func TestAddExclude(t *testing.T) { |
| for _, tt := range addExcludeTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| testEdit(t, tt.in, tt.out, true, func(f *File) error { |
| return f.AddExclude(tt.path, tt.version) |
| }) |
| }) |
| } |
| } |
| |
| func TestAddRetract(t *testing.T) { |
| for _, tt := range addRetractTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| testEdit(t, tt.in, tt.out, true, func(f *File) error { |
| return f.AddRetract(VersionInterval{Low: tt.low, High: tt.high}, tt.rationale) |
| }) |
| }) |
| } |
| } |
| |
| func TestDropRetract(t *testing.T) { |
| for _, tt := range dropRetractTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| testEdit(t, tt.in, tt.out, true, func(f *File) error { |
| if err := f.DropRetract(VersionInterval{Low: tt.low, High: tt.high}); err != nil { |
| return err |
| } |
| f.Cleanup() |
| return nil |
| }) |
| }) |
| } |
| } |
| |
| func TestRetractRationale(t *testing.T) { |
| for _, tt := range retractRationaleTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| f, err := Parse("in", []byte(tt.in), nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if len(f.Retract) != 1 { |
| t.Fatalf("got %d retract directives; want 1", len(f.Retract)) |
| } |
| if got := f.Retract[0].Rationale; got != tt.want { |
| t.Errorf("got %q; want %q", got, tt.want) |
| } |
| }) |
| } |
| } |
| |
| func TestModuleDeprecated(t *testing.T) { |
| for _, tt := range moduleDeprecatedTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| f, err := Parse("in", []byte(tt.in), nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if f.Module.Deprecated != tt.want { |
| t.Errorf("got %q; want %q", f.Module.Deprecated, tt.want) |
| } |
| }) |
| } |
| } |
| |
| func TestSortBlocks(t *testing.T) { |
| for _, tt := range sortBlocksTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| testEdit(t, tt.in, tt.out, tt.strict, func(f *File) error { |
| f.SortBlocks() |
| return nil |
| }) |
| }) |
| } |
| } |
| |
| func testEdit(t *testing.T, in, want string, strict bool, transform func(f *File) error) *File { |
| t.Helper() |
| parse := Parse |
| if !strict { |
| parse = ParseLax |
| } |
| f, err := parse("in", []byte(in), nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| g, err := parse("out", []byte(want), nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| golden, err := g.Format() |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| if err := transform(f); err != nil { |
| t.Fatal(err) |
| } |
| out, err := f.Format() |
| if err != nil { |
| t.Fatal(err) |
| } |
| if !bytes.Equal(out, golden) { |
| t.Errorf("have:\n%s\nwant:\n%s", out, golden) |
| } |
| |
| return f |
| } |
| |
| func TestAddRetractValidateVersion(t *testing.T) { |
| for _, tt := range addRetractValidateVersionTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| f := new(File) |
| if tt.path != "" { |
| if err := f.AddModuleStmt(tt.path); err != nil { |
| t.Fatal(err) |
| } |
| t.Logf("module %s", AutoQuote(tt.path)) |
| } |
| interval := VersionInterval{Low: tt.low, High: tt.high} |
| if err := f.AddRetract(interval, ``); err == nil || err.Error() != tt.wantErr { |
| errStr := "<nil>" |
| if err != nil { |
| errStr = fmt.Sprintf("%#q", err) |
| } |
| t.Fatalf("f.AddRetract(%+v, ``) = %s\nwant %#q", interval, errStr, tt.wantErr) |
| } |
| }) |
| } |
| } |
| |
| func TestAddExcludeValidateVersion(t *testing.T) { |
| for _, tt := range addExcludeValidateVersionTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| f, err := Parse("in", []byte("module m"), nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if err = f.AddExclude(tt.path, tt.version); err == nil || err.Error() != tt.wantErr { |
| errStr := "<nil>" |
| if err != nil { |
| errStr = fmt.Sprintf("%#q", err) |
| } |
| t.Fatalf("f.AddExclude(%q, %q) = %s\nwant %#q", tt.path, tt.version, errStr, tt.wantErr) |
| } |
| }) |
| } |
| } |
| |
| func TestFixVersion(t *testing.T) { |
| for _, tt := range fixVersionTests { |
| t.Run(tt.desc, func(t *testing.T) { |
| inFile, err := Parse("in", []byte(tt.in), tt.fix) |
| if err != nil { |
| if tt.wantErr == "" { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| if errMsg := err.Error(); !strings.Contains(errMsg, tt.wantErr) { |
| t.Fatalf("got error %q; want error containing %q", errMsg, tt.wantErr) |
| } |
| return |
| } |
| got, err := inFile.Format() |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| outFile, err := Parse("out", []byte(tt.want), nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| want, err := outFile.Format() |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| if !bytes.Equal(got, want) { |
| t.Fatalf("got:\n%s\nwant:\n%s", got, want) |
| } |
| }) |
| } |
| } |