github.com/go-chrono/chrono@v0.0.0-20240102183611-532f0d0d7c34/period_test.go (about)

     1  package chrono_test
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/go-chrono/chrono"
     8  )
     9  
    10  func TestPeriod_Format(t *testing.T) {
    11  	for _, tt := range []struct {
    12  		name     string
    13  		input    chrono.Period
    14  		expected string
    15  	}{
    16  		{
    17  			name:     "YMWD",
    18  			input:    chrono.Period{Years: 14, Months: 8, Weeks: 4, Days: 2},
    19  			expected: "P14Y8M4W2D",
    20  		},
    21  		{
    22  			name:     "YMW",
    23  			input:    chrono.Period{Years: 14, Months: 8, Weeks: 4},
    24  			expected: "P14Y8M4W",
    25  		},
    26  		{
    27  			name:     "YM",
    28  			input:    chrono.Period{Years: 14, Months: 8},
    29  			expected: "P14Y8M",
    30  		},
    31  		{
    32  			name:     "Y",
    33  			input:    chrono.Period{Years: 14},
    34  			expected: "P14Y",
    35  		},
    36  		{
    37  			name:     "YWD",
    38  			input:    chrono.Period{Years: 14, Weeks: 4, Days: 2},
    39  			expected: "P14Y4W2D",
    40  		},
    41  		{
    42  			name:     "YW",
    43  			input:    chrono.Period{Years: 14, Weeks: 4},
    44  			expected: "P14Y4W",
    45  		},
    46  		{
    47  			name:     "YMD",
    48  			input:    chrono.Period{Years: 14, Months: 8, Days: 2},
    49  			expected: "P14Y8M2D",
    50  		},
    51  		{
    52  			name:     "YD",
    53  			input:    chrono.Period{Years: 14, Days: 2},
    54  			expected: "P14Y2D",
    55  		},
    56  		{
    57  			name:     "MWD",
    58  			input:    chrono.Period{Months: 8, Weeks: 4, Days: 2},
    59  			expected: "P8M4W2D",
    60  		},
    61  		{
    62  			name:     "MW",
    63  			input:    chrono.Period{Months: 8, Weeks: 4},
    64  			expected: "P8M4W",
    65  		},
    66  		{
    67  			name:     "M",
    68  			input:    chrono.Period{Months: 8},
    69  			expected: "P8M",
    70  		},
    71  		{
    72  			name:     "MD",
    73  			input:    chrono.Period{Months: 8, Days: 2},
    74  			expected: "P8M2D",
    75  		},
    76  		{
    77  			name:     "WD",
    78  			input:    chrono.Period{Weeks: 4, Days: 2},
    79  			expected: "P4W2D",
    80  		},
    81  		{
    82  			name:     "D",
    83  			input:    chrono.Period{Days: 2},
    84  			expected: "P2D",
    85  		},
    86  		{
    87  			name:     "empty",
    88  			input:    chrono.Period{},
    89  			expected: "P0D",
    90  		},
    91  	} {
    92  		t.Run(tt.name, func(t *testing.T) {
    93  			if out := tt.input.Format(); out != tt.expected {
    94  				t.Errorf("formatted period = %s, want %s", out, tt.expected)
    95  			}
    96  		})
    97  	}
    98  }
    99  
   100  func TestPeriod_Parse(t *testing.T) {
   101  	for _, tt := range []struct {
   102  		name     string
   103  		input    string
   104  		expected chrono.Period
   105  	}{
   106  		{
   107  			name:     "valid YMWD",
   108  			input:    "P14Y8M5W2D",
   109  			expected: chrono.Period{Years: 14, Months: 8, Weeks: 5, Days: 2},
   110  		},
   111  		{
   112  			name:     "valid YMD",
   113  			input:    "P14Y8M2D",
   114  			expected: chrono.Period{Years: 14, Months: 8, Days: 2},
   115  		},
   116  		{
   117  			name:     "valid YM",
   118  			input:    "P14Y8M",
   119  			expected: chrono.Period{Years: 14, Months: 8},
   120  		},
   121  		{
   122  			name:     "valid YD",
   123  			input:    "P14Y2D",
   124  			expected: chrono.Period{Years: 14, Days: 2},
   125  		},
   126  		{
   127  			name:     "valid Y",
   128  			input:    "P14Y",
   129  			expected: chrono.Period{Years: 14},
   130  		},
   131  		{
   132  			name:     "valid MWD",
   133  			input:    "P8M5W2D",
   134  			expected: chrono.Period{Months: 8, Weeks: 5, Days: 2},
   135  		},
   136  		{
   137  			name:     "valid MW",
   138  			input:    "P8M5W",
   139  			expected: chrono.Period{Months: 8, Weeks: 5},
   140  		},
   141  		{
   142  			name:     "valid MD",
   143  			input:    "P8M2D",
   144  			expected: chrono.Period{Months: 8, Days: 2},
   145  		},
   146  		{
   147  			name:     "valid WD",
   148  			input:    "P5W2D",
   149  			expected: chrono.Period{Weeks: 5, Days: 2},
   150  		},
   151  		{
   152  			name:     "valid M",
   153  			input:    "P8M",
   154  			expected: chrono.Period{Months: 8},
   155  		},
   156  		{
   157  			name:     "valid W",
   158  			input:    "P6W",
   159  			expected: chrono.Period{Weeks: 6},
   160  		},
   161  		{
   162  			name:     "valid D",
   163  			input:    "P2D",
   164  			expected: chrono.Period{Days: 2},
   165  		},
   166  	} {
   167  		t.Run(tt.name, func(t *testing.T) {
   168  			var p chrono.Period
   169  			if err := p.Parse(tt.input); err != nil {
   170  				t.Errorf("failed to parse period: %v", err)
   171  			} else if !p.Equal(tt.expected) {
   172  				t.Errorf("parsed period = %v, want %v", p, tt.expected)
   173  			}
   174  		})
   175  	}
   176  }
   177  
   178  func TestParseDuration(t *testing.T) {
   179  	for _, tt := range []struct {
   180  		name     string
   181  		input    string
   182  		period   chrono.Period
   183  		duration chrono.Duration
   184  	}{
   185  		{
   186  			name:     "period only",
   187  			input:    "P2.5Y",
   188  			period:   chrono.Period{Years: 2.5},
   189  			duration: chrono.Duration{},
   190  		},
   191  		{
   192  			name:     "duration only",
   193  			input:    "PT6.5H",
   194  			period:   chrono.Period{},
   195  			duration: chrono.DurationOf((6 * chrono.Hour) + (30 * chrono.Minute)),
   196  		},
   197  		{
   198  			name:     "both period and duration",
   199  			input:    "P2.5YT6.5H",
   200  			period:   chrono.Period{Years: 2.5},
   201  			duration: chrono.DurationOf((6 * chrono.Hour) + (30 * chrono.Minute)),
   202  		},
   203  	} {
   204  		t.Run(tt.name, func(t *testing.T) {
   205  			run := func() {
   206  				if p, d, err := chrono.ParseDuration(tt.input); err != nil {
   207  					t.Errorf("failed to parse period & duration: %v", err)
   208  				} else if !p.Equal(tt.period) {
   209  					t.Errorf("parsed period = %v, want %v", p, tt.period)
   210  				} else if d.Compare(tt.duration) != 0 {
   211  					t.Errorf("parsed duration = %v, want %v", d, tt.duration)
   212  				}
   213  			}
   214  
   215  			t.Run("dots", func(t *testing.T) {
   216  				run()
   217  			})
   218  
   219  			t.Run("commas", func(t *testing.T) {
   220  				tt.input = strings.ReplaceAll(tt.input, ".", ",")
   221  				run()
   222  			})
   223  		})
   224  	}
   225  
   226  	t.Run("invalid strings", func(t *testing.T) {
   227  		for _, tt := range []string{
   228  			"P",
   229  			"PT",
   230  		} {
   231  			if _, _, err := chrono.ParseDuration(tt); err == nil {
   232  				t.Error("expecting error but got nil")
   233  			}
   234  		}
   235  	})
   236  }