## Test the constructor
%!test
%! Name = {"John"; "Mary"; "Peter"; "Barbara"};
%! Age = [23; 34; 42; 28];
%! Height = [167; 163; 183; 178];
%! T = table (Name, Age, Height);
%! assert (size (T), [4, 3]);
%! assert (size (T.Age), [4, 1]);
%! assert (mean (T.Age), 31.75);
%! varnames = T.Properties.VariableNames;
%! assert (varnames, {"Name", "Age", "Height"});
%!test
%! Name = {"John"; "Mary"; "Peter"; "Barbara"};
%! Age = [23; 34; 42; 28];
%! Height = [167; 163; 183; 178];
%! T = table (Name, Age, Height);
%! BloodPressure = [114 83; 119 75; 115 73; 107 80];
%! T = table (Name, Age, Height, BloodPressure);
%! assert (size (T), [4, 4]);
%! assert (size (T.BloodPressure), [4, 2]);
%!test
%! Name = {"John"; "Mary"; "Peter"; "Barbara"};
%! Age = [23; 34; 42; 28];
%! Height = [167; 163; 183; 178];
%! T = table (Name, Age, Height, "VariableNames", {"A", "B", "C"});
%! assert (T.Properties.VariableNames, {"A", "B", "C"});
%!test
%! sz = [4 3];
%! varTypes = {"double", "datetime", "string"};
%! T = table("Size", sz, "VariableTypes", varTypes);
%! assert (size (T), [4, 3]);
%! assert (T.Properties.VariableNames, {"Var1", "Var2", "Var3"});
%!test
%! sz = [4 3];
%! varTypes = {"double", "datetime", "string"};
%! T = table("Size", sz, "VariableTypes", varTypes, ...
%!           "VariableNames", {"A", "B", "C"});
%! assert (size (T), [4, 3]);
%! assert (T.Properties.VariableNames, {"A", "B", "C"});
%!test
%! sz = [4 3];
%! varTypes = {"double", "datetime", "table"};
%! T = table("Size", sz, "VariableTypes", varTypes, ...
%!           "VariableNames", {"A", "B", "C"});
%! assert (size (T), [4, 3]);
%! assert (size (T.C), [0, 1]);
%! assert (class (T.A), "double");
%! assert (class (T.B), "datetime");
%! assert (class (T.C), "table");

## Test 'subref' and 'subsasgn' methods
%!shared LastName, Age, Smoker, Height, Weight, BloodPressure, T, tblA
%! LastName = {"Sanchez"; "Johnson"; "Li"; "Diaz"; "Brown"};
%! Age = [38; 43; 38; 40; 49];
%! Smoker = logical ([1; 0; 1; 0; 1]);
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 133; 119];
%! BloodPressure = [124, 93; 109, 77; 125, 83; 117, 75; 122, 80];
%! T = table (Age, Smoker, Height, Weight, BloodPressure);
%!assert (size (T(1,:)), [1, 5]);
%!assert (class (T(1,:)), "table");
%!assert (size (T{1,:}), [1, 6]);
%!assert (T{1,:}, [38, 1, 71, 176, 124, 93]);
%!assert (T{:,2}, logical([1; 0; 1; 0; 1]));
%!assert (T{:,"Smoker"}, logical([1; 0; 1; 0; 1]));
%!assert (T{:,"Height"}, [71; 69; 64; 67; 64]);
%!assert (size(T{:,"Smoker"}), [5, 1]);
%!assert (size(T{:,"Height"}), [5, 1]);
%!assert (T.Variables, [Age, Smoker, Height, Weight, BloodPressure]);
%!assert (isempty (T.Properties.RowNames), true);
%!assert (numel (T.Properties.VariableNames), 5);
%!test
%! T.Properties.Description = "text";
%! assert (T.Properties.Description, "text");
%!assert (size (T(:,{"Age", "Smoker"})), [5, 2]);
%!assert (T{:,{"Age", "Smoker"}}, [Age, Smoker]);
%!test
%! T = table (Age, Smoker);
%! T.("29-May-2019 Blood Pressure Reading") = BloodPressure;
%! assert (T.("29-May-2019 Blood Pressure Reading"), BloodPressure);
%!test
%! T = table (Age, Smoker);
%! T.Height = Height;
%! T.Weight = Weight;
%! assert (size (T), [5, 4]);
%! assert (T.Weight, Weight);
%! assert (T.Weight, T{:,"Weight"});
%! assert (T.Weight, T{:,4});
%!test
%! T.Weight(1) = 25;
%! assert (T.Weight, [25;Weight(2:end)]);
%!test
%! T.Weight([1,3]) = 25;
%! assert (T.Weight, [25;Weight(2);25;Weight(4:end)]);
%!test
%! T.Weight([1,3]) = 25;
%! assert (T.Weight, [25;Weight(2);25;Weight(4:end)]);
%!test
%! T.Weight([1:3,5]) = 25;
%! assert (T.Weight, [25;25;25;Weight(4);25]);
%!test
%! T = table (LastName, Age, Smoker, Height, Weight);
%! T.Properties.RowNames = string (LastName);
%!test
%! T = table (LastName, Age, Smoker, Height, Weight);
%! T.Properties.RowNames = 'LastName';
%!test
%! T = table (LastName, Age, Smoker, Height, Weight);
%! T.Properties.RowNames = {'LastName'};
%!test
%! T = table (LastName, Age, Smoker, Height, Weight);
%! T.Properties.RowNames = ['LastName'];
%!test
%! T = table (LastName, Age, Smoker, Height, Weight);
%! assert (isempty (T.Row), true);
%! T.Properties.DimensionNames(1) = 'Patients';
%! assert (isempty (T.Patients), true);
%!test
%! T.Properties.RowNames = "LastName";
%! assert (isempty (T.Patients), false);
%! T.Properties.DimensionNames(2) = 'Data';
%! assert (T.Data, [Age,Smoker,Height,Weight]);
%!test
%! T = table (Age, Smoker, Height, Weight, BloodPressure);
%! assert (T{1, @isnumeric}, [38, 71, 176, 124, 93]);
%! assert (T{1, vartype ("numeric")}, [38, 71, 176, 124, 93]);
%!test
%! T1 = table (LastName, Age);
%! assert (T1{:, @iscellstr}, LastName);
%! assert (T1{:, @isnumeric}, Age);
%! assert (T1(:, @iscellstr).LastName, LastName)
%! assert (T1(:, @isnumeric).Age, Age)
%!test
%! T1 = table (LastName, Age);
%! assert (T1{:, @iscellstr}, LastName);
%! assert (T1{:, @isnumeric}, Age);
%!test
%! T1 = table (LastName, Age, Height);
%! assert (T1{:, @iscellstr}, LastName);
%! assert (class (T1(:, @isnumeric)), "table");
%! assert (size (T1(:, @isnumeric)), [5, 2]);

## Test "end" keyword
%!test
%! t = table ([1;2;3], [4;5;6], [7;8;9], 'VariableNames', {'A', 'B', 'C'}, ...
%!                                       'RowNames', {'Row1', 'Row2', 'Row3'});
%! out = t(:,end);
%! assert (out.Properties.VariableNames, {'C'});
%! assert (out.Properties.RowNames, {'Row1'; 'Row2'; 'Row3'});
%! assert (out.C, [7; 8; 9]);
%! out = t{:,end};
%! assert (out, [7; 8; 9]);
%!test
%! t = table ([1;2;3], [4;5;6], [7;8;9], 'VariableNames', {'A', 'B', 'C'}, ...
%!                                       'RowNames', {'Row1', 'Row2', 'Row3'});
%! out = t(end, :);
%! assert (out.Properties.VariableNames, {'A', 'B', 'C'});
%! assert (out.Properties.RowNames, {'Row3'});
%! assert ([out.A, out.B, out.C], [3, 6, 9]);
%! out = t{end,:};
%! assert (out, [3, 6, 9]);

## Test **summary information** methods
%!test
%! T = table (Age, Smoker, Height, Weight, BloodPressure);
%! assert (table2array (T), [Age, Smoker, Height, Weight, BloodPressure]);
%!test
%! C = table2cell (T);
%! assert (cell2mat (C(:,[1:4])), [Age, Smoker, Height, Weight]);
%!test
%! S = table2struct (T);
%! assert ([S.Age], Age');
%! assert (reshape ([S.BloodPressure], 2, 5)', BloodPressure);
%! assert (numel (S), height (T));
%!test
%! S = table2struct (T, "ToScalar", true);
%! assert (S.Age, Age);
%! assert (S.BloodPressure, BloodPressure);
%! assert (numel (S), 1);
%!test
%! t = summary (T);
%! assert (isstruct (t), true);
%! assert ([t.Age.Min, t.Age.Median, t.Age.Max], [38, 40, 49]);
%! assert (t.Smoker.Size, [5, 1]);
%! assert (t.BloodPressure.Size, [5, 2]);
%!assert (height (T), 5);
%!assert (width (T), 5);
%!assert (height (head (T, 3)), 3);
%!assert (height (head (T, 8)), 5);
%!assert (height (head (T)), 5);
%!assert (height (tail (T, 3)), 3);
%!assert (height (tail (T, 8)), 5);
%!assert (height (tail (T)), 5);

## Test 'sortrows' and 'issortedrows' methods
%!test
%! tblA = table (Age, Height, Weight, BloodPressure, 'RowNames', LastName);
%! assert (issortedrows (tblA, "RowNames"), false);
%! [sorted_tblA, index] = sortrows (tblA, "RowNames");
%! assert (index, [5; 4; 2; 3; 1]);
%! assert (issortedrows (sorted_tblA, "RowNames"), true);
%! [sorted_tblA, index] = sortrows (tblA, "RowNames", "descend");
%! assert (index, [1; 3; 2; 4; 5]);
%! assert (issortedrows (sorted_tblA, "RowNames", "descend"), true);
%!test
%! tblA.Properties.DimensionNames(1) = "Patients";
%! assert (issortedrows (tblA, "Patients"), false);
%! [sorted_tblA, index] = sortrows (tblA, "Patients");
%! assert (index, [5; 4; 2; 3; 1]);
%! assert (issortedrows (sorted_tblA, "Patients"), true);
%! [sorted_tblA, index] = sortrows (tblA, "Patients", "descend");
%! assert (index, [1; 3; 2; 4; 5]);
%! assert (issortedrows (sorted_tblA, "Patients", "descend"), true);
%!test
%! [sorted_tblA, index] = sortrows (tblA);
%! assert (index, [3; 1; 4; 2; 5]);
%! assert (issortedrows (sorted_tblA), true);
%! [sorted_tblA, index] = sortrows (tblA, [], "ascend");
%! assert (index, [3; 1; 4; 2; 5]);
%! assert (issortedrows (sorted_tblA, [], "ascend"), true);
%! [sorted_tblA, index] = sortrows (tblA, [], "descend");
%! assert (index, [5; 2; 4; 1; 3]);
%! assert (issortedrows (sorted_tblA, [], "descend"), true);
%!test
%! [tblB, index] = sortrows (tblA, "Height");
%! assert (index, [3; 5; 4; 2; 1]);
%! assert (tblB.Properties.RowNames, ...
%!         {"Li"; "Brown"; "Diaz"; "Johnson"; "Sanchez"})
%! assert (issortedrows (tblB, "Height"), true);
%!test
%! LastName = {"Sweet"; "Jacobson"; "Wang"; "Joiner"; "Berger"};
%! tblA = table (Age, Height, Weight, BloodPressure, 'RowNames', LastName);
%! [tblB, index] = sortrows (tblA, {"Height", "Weight"}, {"ascend", "descend"});
%! assert (index, [3; 5; 4; 2; 1]);
%! assert (tblB.Properties.RowNames, ...
%!         {"Wang"; "Berger"; "Joiner"; "Jacobson"; "Sweet"})
%! assert (issortedrows (tblB, {"Height", "Weight"}, ...
%!                             {"ascend", "descend"}), true);
%!test
%! [tblB, index] = sortrows (tblA, {"BloodPressure"}, {"ascend"});
%! assert (index, [2; 4; 5; 1; 3]);
%! assert (tblB.BloodPressure, sortrows (BloodPressure));
%! assert (issortedrows (tblB, {"BloodPressure"}, {"ascend"}), true);
%! [tblB, index] = sortrows (tblA, {"BloodPressure"}, {"descend"});
%! assert (index, flip ([2; 4; 5; 1; 3]));
%! assert (tblB.BloodPressure, sortrows (BloodPressure, -1));
%! assert (issortedrows (tblB, "BloodPressure", "descend"), true);
%!test
%! [tblB, index] = sortrows (tblA, {"Height", "RowNames"}, {"ascend"});
%! assert (index, [5; 3; 4; 2; 1]);
%! assert (tblB.Properties.RowNames, ...
%!         {"Berger"; "Wang"; "Joiner"; "Jacobson"; "Sweet"})
%! assert (tblB.Height, sortrows (Height));
%! assert (issortedrows (tblB, {"Height", "RowNames"}, {"ascend"}), true);
%! [tblB, index] = sortrows (tblA, {"Height", "RowNames"}, ...
%!                                 {"ascend", "descend"});
%! assert (index, [3; 5; 4; 2; 1]);
%! assert (tblB.Properties.RowNames, ...
%!         {"Wang"; "Berger"; "Joiner"; "Jacobson"; "Sweet"})
%! assert (issortedrows (tblB, {"Height", "RowNames"}, ...
%!                             {"ascend", "descend"}), true);
%!test
%! [tblB, index] = sortrows (tblA, [true, true, false, false]);
%! assert (index, [3; 1; 4; 2; 5]);
%! assert (issortedrows (tblB, [true, true, false, false]), true);
%! [tblB, index] = sortrows (tblA, [true, true, false, false], "ascend");
%! assert (index, [3; 1; 4; 2; 5]);
%! assert (issortedrows (tblB, [true, true, false, false], "ascend"), true);
%! [tblB, index] = sortrows (tblA, [true, true, false, false], "descend");
%! assert (index, flip ([3; 1; 4; 2; 5]));
%! assert (issortedrows (tblB, [true, true, false, false], "descend"), true);
%! [tblB, index] = sortrows (tblA, [true, true, false, false], ...
%!                                 {"ascend", "descend"});
%! assert (index, [1; 3; 4; 2; 5]);
%! assert (issortedrows (tblB, [true, true, false, false], ...
%!                             {"ascend", "descend"}), true);
%!test
%! [sorted_tblA, indexN] = sortrows (tblA, 1);
%! assert (issortedrows (sorted_tblA, 1), true);
%! [sorted_tblA, indexV] = sortrows (tblA, "Age");
%! assert (issortedrows (sorted_tblA, "Age"), true);
%! assert (indexN, indexV);
%! [sorted_tblA, indexN] = sortrows (tblA, -1);
%! assert (issortedrows (sorted_tblA, -1), true);
%! [sorted_tblA, indexV] = sortrows (tblA, "Age", "descend");
%! assert (issortedrows (sorted_tblA, "Age", "descend"), true);
%! assert (indexN, indexV);
%! [sorted_tblA, indexN] = sortrows (tblA, -1, "ascend");
%! assert (issortedrows (sorted_tblA, -1, "ascend"), true);
%! [~, indexV] = sortrows (tblA, "Age");
%! assert (indexN, indexV);
%! [sorted_tblA, indexN] = sortrows (tblA, [-1, 2]);
%! assert (issortedrows (sorted_tblA, [-1, 2]), true);
%! [~, indexV] = sortrows (tblA, {"Age", "Height"}, {"descend", "ascend"});
%! assert (indexN, indexV);
%!test
%! TT = table (Age, table (Age, Height), BloodPressure, 'RowNames', LastName);
%! [sorted_TT, index] = sortrows (TT);
%! assert (index, [3; 1; 4; 2; 5]);
%! assert (issortedrows (sorted_TT), true);
%! [sorted_TT, index] = sortrows (TT, [1, 2]);
%! assert (index, [3; 1; 4; 2; 5]);
%! assert (issortedrows (sorted_TT, [1, 2]), true);
%! [sorted_TT, index] = sortrows (TT, [1, -2]);
%! assert (index, [1; 3; 4; 2; 5]);
%! assert (issortedrows (sorted_TT, [1, -2]), true);
%!test
%! Weights = [176;NaN;131;133;NaN];
%! tblN = table (Age, Height, Weights, BloodPressure, 'RowNames', LastName);
%! [tblB, index] = sortrows (tblN, "Weights", "MissingPlacement", "first");
%! assert (index, [2; 5; 3; 4; 1]);
%! assert (issortedrows (tblB, "Weights", "MissingPlacement", "first"), true);
%! [tblB, index] = sortrows (tblN, "Weights");
%! assert (index, [3; 4; 1; 2; 5]);
%! assert (issortedrows (tblB, "Weights"), true);
%!test
%! tblN = table (Age, Height, Weight, BloodPressure, LastName);
%! [tblB, index] = sortrows (tblN, vartype ("numeric"));
%! assert (index, [3; 1; 4; 2; 5]);
%! assert (issortedrows (tblB, vartype ("numeric")), true);
%! [tblB, index] = sortrows (tblN, vartype ("cellstr"));
%! assert (index, [5; 2; 4; 1; 3]);
%! assert (issortedrows (tblB, vartype ("cellstr")), true);

## Test 'unique' method
%!test
%! Name = {'Fred'; 'Betty'; 'Bob'; 'George'; 'Jane'};
%! Age = [38; 43; 38; 40; 38];
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 185; 131];
%! A = table (Age, Height, Weight, 'RowNames', Name);
%! [C, ia, ic] = unique (A);
%! assert (ia, [3; 1; 4; 2]);
%! assert (ic, [2; 4; 1; 3; 1]);
%! assert (C.Age, [38; 38; 40; 43]);
%! assert (C.Height, [64; 71; 67; 69]);
%! assert (C.Weight, [131; 176; 185; 163]);
%! assert (C.Properties.RowNames, {'Bob'; 'Fred'; 'George'; 'Betty'});
%!test
%! Name = {'Fred'; 'Betty'; 'Bob'; 'George'; 'Jane'};
%! Age = [38; 43; 38; 40; 38];
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 185; 131];
%! A = table (Age, Height, Weight, 'RowNames', Name);
%! [C, ia, ic] = unique (A, "sorted");
%! assert (ia, [3; 1; 4; 2]);
%! assert (ic, [2; 4; 1; 3; 1]);
%! assert (C.Age, [38; 38; 40; 43]);
%! assert (C.Height, [64; 71; 67; 69]);
%! assert (C.Weight, [131; 176; 185; 163]);
%! assert (C.Properties.RowNames, {'Bob'; 'Fred'; 'George'; 'Betty'});
%!test
%! Name = {'Fred'; 'Betty'; 'Bob'; 'George'; 'Jane'};
%! Age = [38; 43; 38; 40; 38];
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 185; 131];
%! A = table (Age, Height, Weight, 'RowNames', Name);
%! [C, ia, ic] = unique (A, "stable");
%! assert (ia, [1; 2; 3; 4]);
%! assert (ic, [1; 2; 3; 4; 3]);
%! assert (C.Age, [38; 43; 38; 40]);
%! assert (C.Height, [71; 69; 64; 67]);
%! assert (C.Weight, [176; 163; 131; 185]);
%! assert (C.Properties.RowNames, {'Fred'; 'Betty'; 'Bob'; 'George'});
%!test
%! Name = {'Fred'; 'Betty'; 'Bob'; 'George'; 'Jane'};
%! Age = [38; 43; 38; 40; 38];
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 185; 131];
%! A = table (Age, Height, Weight, 'RowNames', Name);
%! [C, ia, ic] = unique (A, "first");
%! assert (ia, [3; 1; 4; 2]);
%! assert (ic, [2; 4; 1; 3; 1]);
%! assert (C.Age, [38; 38; 40; 43]);
%! assert (C.Height, [64; 71; 67; 69]);
%! assert (C.Weight, [131; 176; 185; 163]);
%! assert (C.Properties.RowNames, {'Bob'; 'Fred'; 'George'; 'Betty'});
%!test
%! Name = {'Fred'; 'Betty'; 'Bob'; 'George'; 'Jane'};
%! Age = [38; 43; 38; 40; 38];
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 185; 131];
%! A = table (Age, Height, Weight, 'RowNames', Name);
%! [C, ia, ic] = unique (A, "last");
%! assert (ia, [5; 1; 4; 2]);
%! assert (ic, [2; 4; 1; 3; 1]);
%! assert (C.Age, [38; 38; 40; 43]);
%! assert (C.Height, [64; 71; 67; 69]);
%! assert (C.Weight, [131; 176; 185; 163]);
%! assert (C.Properties.RowNames, {'Jane'; 'Fred'; 'George'; 'Betty'});

## Test 'topkrows' method
%!test
%! LastName = {"Sanchez"; "Johnson"; "Li"; "Diaz"; "Brown"};
%! Age = [38; 43; 38; 40; 49];
%! Smoker = logical ([1; 0; 1; 0; 1]);
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 133; 119];
%! BloodPressure = [124, 93; 109, 77; 125, 83; 117, 75; 122, 80];
%! tblA = table (Age, Height, Weight, BloodPressure, 'RowNames', LastName);
%! [sorted_tblA, index] = topkrows (tblA, 3, "RowNames");
%! assert (index, [5; 4; 2]);
%! assert (issortedrows (sorted_tblA, "RowNames"), true);
%! [sorted_tblA, index] = topkrows (tblA, 4, "RowNames", "descend");
%! assert (index, [1; 3; 2; 4]);
%! assert (issortedrows (sorted_tblA, "RowNames", "descend"), true);
%!test
%! tblA.Properties.DimensionNames(1) = "Patients";
%! assert (issortedrows (tblA, "Patients"), false);
%! [sorted_tblA, index] = topkrows (tblA, 2, "Patients");
%! assert (index, [5; 4]);
%! assert (issortedrows (sorted_tblA, "Patients"), true);
%! [sorted_tblA, index] = topkrows (tblA, 5, "Patients", "descend");
%! assert (index, [1; 3; 2; 4; 5]);
%! assert (issortedrows (sorted_tblA, "Patients", "descend"), true);
%!test
%! [sorted_tblA, index] = topkrows (tblA, 3);
%! assert (index, [3; 1; 4]);
%! assert (issortedrows (sorted_tblA), true);
%! [sorted_tblA, index] = topkrows (tblA, 3, ":", "ascend");
%! assert (index, [3; 1; 4]);
%! assert (issortedrows (sorted_tblA, [], "ascend"), true);
%! [sorted_tblA, index] = topkrows (tblA, 3, [], "descend");
%! assert (index, [5; 2; 4]);
%! assert (issortedrows (sorted_tblA, [], "descend"), true);
%!test
%! [tblB, index] = topkrows (tblA, 3, "Height");
%! assert (index, [3; 5; 4]);
%! assert (tblB.Properties.RowNames, {"Li"; "Brown"; "Diaz"});
%! assert (issortedrows (tblB, "Height"), true);
%!test
%! LastName = {"Sweet"; "Jacobson"; "Wang"; "Joiner"; "Berger"};
%! tblA = table (Age, Height, Weight, BloodPressure, 'RowNames', LastName);
%! [tblB, index] = topkrows (tblA, 2, {"Height", "Weight"}, ...
%!                                    {"ascend", "descend"});
%! assert (index, [3; 5]);
%! assert (tblB.Properties.RowNames, {"Wang"; "Berger"});
%! assert (issortedrows (tblB, {"Height", "Weight"}, ...
%!                             {"ascend", "descend"}), true);
%!test
%! [tblB, index] = topkrows (tblA, 4, {"BloodPressure"}, {"ascend"});
%! assert (index, [2; 4; 5; 1]);
%! assert (issortedrows (tblB, {"BloodPressure"}, {"ascend"}), true);
%! [tblB, index] = topkrows (tblA, 3, {"BloodPressure"}, {"descend"});
%! assert (index, [3; 1; 5]);
%! assert (issortedrows (tblB, "BloodPressure", "descend"), true);
%!test
%! [tblB, index] = topkrows (tblA, 3, {"Height", "RowNames"}, {"ascend"});
%! assert (index, [5; 3; 4]);
%! assert (tblB.Properties.RowNames, {"Berger"; "Wang"; "Joiner"})
%! assert (issortedrows (tblB, {"Height", "RowNames"}, {"ascend"}), true);
%! [tblB, index] = topkrows (tblA, 4, {"Height", "RowNames"}, ...
%!                                    {"ascend", "descend"});
%! assert (index, [3; 5; 4; 2]);
%! assert (tblB.Properties.RowNames, {"Wang"; "Berger"; "Joiner"; "Jacobson"});
%! assert (issortedrows (tblB, {"Height", "RowNames"}, ...
%!                             {"ascend", "descend"}), true);
%!test
%! [tblB, index] = topkrows (tblA, 3, [true, true, false, false]);
%! assert (index, [3; 1; 4]);
%! assert (issortedrows (tblB, [true, true, false, false]), true);
%! [tblB, index] = topkrows (tblA, 2, [true, true, false, false], "ascend");
%! assert (index, [3; 1]);
%! assert (issortedrows (tblB, [true, true, false, false], "ascend"), true);
%! [tblB, index] = topkrows (tblA, 5, [true, true, false, false], "descend");
%! assert (index, flip ([3; 1; 4; 2; 5]));
%! assert (issortedrows (tblB, [true, true, false, false], "descend"), true);
%! [tblB, index] = topkrows (tblA, 6, [true, true, false, false], ...
%!                                    {"ascend", "descend"});
%! assert (index, [1; 3; 4; 2; 5]);
%! assert (issortedrows (tblB, [true, true, false, false], ...
%!                             {"ascend", "descend"}), true);
%!test
%! [sorted_tblA, indexN] = topkrows (tblA, 2, 1);
%! assert (issortedrows (sorted_tblA, 1), true);
%! [sorted_tblA, indexV] = topkrows (tblA, 2, "Age");
%! assert (issortedrows (sorted_tblA, "Age"), true);
%! assert (indexN, indexV);
%! [sorted_tblA, indexN] = topkrows (tblA, 3, -1);
%! assert (issortedrows (sorted_tblA, -1), true);
%! [sorted_tblA, indexV] = topkrows (tblA, 3, "Age", "descend");
%! assert (issortedrows (sorted_tblA, "Age", "descend"), true);
%! assert (indexN, indexV);
%! [sorted_tblA, indexN] = topkrows (tblA, 5, -1, "ascend");
%! assert (issortedrows (sorted_tblA, -1, "ascend"), true);
%! [~, indexV] = topkrows (tblA, 5, "Age");
%! assert (indexN, indexV);
%! [sorted_tblA, indexN] = topkrows (tblA, 3, [-1, 2]);
%! assert (issortedrows (sorted_tblA, [-1, 2]), true);
%! [~, indexV] = topkrows (tblA, 3, {"Age", "Height"}, {"descend", "ascend"});
%! assert (indexN, indexV);
%!test
%! TT = table (Age, table (Age, Height), BloodPressure, 'RowNames', LastName);
%! [sorted_TT, index] = topkrows (TT, 4);
%! assert (index, [3; 1; 4; 2]);
%! assert (issortedrows (sorted_TT), true);
%! [sorted_TT, index] = topkrows (TT, 3, [1, 2]);
%! assert (index, [3; 1; 4]);
%! assert (issortedrows (sorted_TT, [1, 2]), true);
%! [sorted_TT, index] = topkrows (TT, 2, [1, -2]);
%! assert (index, [1; 3]);
%! assert (issortedrows (sorted_TT, [1, -2]), true);
%!test
%! Weights = [176;NaN;131;133;NaN];
%! tblN = table (Age, Height, Weights, BloodPressure, 'RowNames', LastName);
%! [tblB, index] = topkrows (tblN, 4, "Weights", "MissingPlacement", "first");
%! assert (index, [2; 5; 3; 4]);
%! assert (issortedrows (tblB, "Weights", "MissingPlacement", "first"), true);
%! [tblB, index] = topkrows (tblN, 3, "Weights");
%! assert (index, [3; 4; 1]);
%! assert (issortedrows (tblB, "Weights"), true);
%!test
%! tblN = table (Age, Height, Weight, BloodPressure, LastName);
%! [tblB, index] = topkrows (tblN, 3, vartype ("numeric"));
%! assert (index, [3; 1; 4]);
%! assert (issortedrows (tblB, vartype ("numeric")), true);
%! [tblB, index] = topkrows (tblN, 3, vartype ("cellstr"));
%! assert (index, [5; 2; 4]);
%! assert (issortedrows (tblB, vartype ("cellstr")), true);

## Test 'addvars' method
%!test
%! load patients
%! T1 = table (Age, Height, Weight);
%! T2 = addvars (T1, ones (size (Age)));
%! assert (size (head (T2, 3)), [3, 4]);
%! assert (T2.Properties.VariableNames, {'Age', 'Height', 'Weight', 'Var4'});
%!test
%! load patients
%! T1 = table (LastName, Age, Height, Weight);
%! assert (size (head (T1, 3)), [3, 4]);
%! assert (T1.Properties.VariableNames, {'LastName', 'Age', 'Height', 'Weight'});
%! T2 = addvars (T1, Gender, Smoker);
%! assert (size (head (T2, 3)), [3, 6]);
%! assert (T2.Properties.VariableNames, ...
%!         {'LastName', 'Age', 'Height', 'Weight', 'Gender', 'Smoker'});
%!test
%! load patients
%! T1 = table (LastName, Gender);
%! assert (size (head (T1, 3)), [3, 2]);
%! assert (T1.Properties.VariableNames, {'LastName', 'Gender'});
%! T2 = addvars (T1, Age, 'Before', 'Gender');
%! assert (size (head (T2, 5)), [5, 3]);
%! assert (T2.Properties.VariableNames, {'LastName', 'Age', 'Gender'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender);
%! assert (size (head (T1, 4)), [4, 3]);
%! assert (T1.Properties.VariableNames, {'LastName', 'Age', 'Gender'});
%! T2 = addvars (T1, Height, Weight, 'After', 'Age');
%! assert (size (head (T2, 4)), [4, 5]);
%! assert (T2.Properties.VariableNames, ...
%!         {'LastName', 'Age', 'Height', 'Weight', 'Gender'});
%!test
%! load patients
%! T1 = table (LastName, Age, Height, Weight, Gender);
%! assert (size (head (T1, 3)), [3, 5]);
%! assert (T1.Properties.VariableNames, ...
%!         {'LastName', 'Age', 'Height', 'Weight', 'Gender'});
%! T2 = addvars (T1, Smoker, 'After', 1);
%! assert (size (head (T2, 3)), [3, 6]);
%! assert (T2.Properties.VariableNames, ...
%!         {'LastName', 'Smoker', 'Age', 'Height', 'Weight', 'Gender'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! assert (size (head (T1, 3)), [3, 4]);
%! assert (T1.Properties.VariableNames, {'LastName', 'Age', 'Gender', 'Smoker'});
%! T2 = addvars (T1, [Diastolic Systolic], 'NewVariableNames', 'BloodPressure');
%! assert (size (head (T2, 3)), [3, 5]);
%! assert (T2.Properties.VariableNames, ...
%!         {'LastName', 'Age', 'Gender', 'Smoker', 'BloodPressure'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! assert (size (head (T1, 3)), [3, 4]);
%! assert (T1.Properties.VariableNames, {'LastName', 'Age', 'Gender', 'Smoker'});
%! T2 = addvars (T1, Height, Weight, 'Before', 'Smoker', ...
%!                                   'NewVariableNames', {'Inches', 'Pounds'});
%! assert (size (head (T2, 3)), [3, 6]);
%! assert (T2.Properties.VariableNames, ...
%!         {'LastName', 'Age', 'Gender', 'Inches', 'Pounds', 'Smoker'});

## Test 'rename' method
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! assert (T1.Properties.VariableNames, {'LastName', 'Age', 'Gender', 'Smoker'});
%! T2 = renamevars (T1, {'LastName', 'Gender'}, {'Name', 'Sex'});
%! assert (T2.Properties.VariableNames, {'Name', 'Age', 'Sex', 'Smoker'});
%!test
%! T1 = array2table (rand (5, 3));
%! assert (T1.Properties.VariableNames, {'Var1', 'Var2', 'Var3'});
%! allVars = 1:width (T1);
%! newNames = cellfun (@(x) sprintf ("Rand%i",x), num2cell (allVars), ...
%!                     "UniformOutput", false);
%! T2 = renamevars (T1, allVars, newNames);
%! assert (T2.Properties.VariableNames, {'Rand1', 'Rand2', 'Rand3'});

## Test 'movevars' method
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! assert (T1.Properties.VariableNames, {'LastName', 'Age', 'Gender', 'Smoker'});
%! T2 = movevars (T1, {'LastName', 'Gender'});
%! assert (T2.Properties.VariableNames, {'Age', 'Smoker', 'LastName', 'Gender'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = movevars (T1, vartype ("cellstr"));
%! assert (T2.Properties.VariableNames, {'Age', 'Smoker', 'LastName', 'Gender'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = movevars (T1, vartype ("numeric"));
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', 'Smoker', 'Age'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = movevars (T1, {'LastName', 'Gender'}, 'After', 'Age');
%! assert (T2.Properties.VariableNames, {'Age', 'LastName', 'Gender', 'Smoker'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = movevars (T1, [true, false, true, false], 'After', 'Age');
%! assert (T2.Properties.VariableNames, {'Age', 'LastName', 'Gender', 'Smoker'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = movevars (T1, [3, 4], 'Before', 'Age');
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', 'Smoker', 'Age'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = movevars (T1, [3, 4], 'Before', 2);
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', 'Smoker', 'Age'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = movevars (T1, [3, 4], 'Before', [false, true, false, false]);
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', 'Smoker', 'Age'});

## Test 'removevars' method
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = removevars (T1, {'LastName', 'Gender'});
%! assert (T2.Properties.VariableNames, {'Age', 'Smoker'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = removevars (T1, [true, false, true, false]);
%! assert (T2.Properties.VariableNames, {'Age', 'Smoker'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = removevars (T1, [1, 3]);
%! assert (T2.Properties.VariableNames, {'Age', 'Smoker'});
%!test
%! load patients
%! T1 = table (LastName, Age, Gender, Smoker);
%! T2 = removevars (T1, vartype ("numeric"));
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', 'Smoker'});

## Test 'splitvars' method
%!test
%! A = [1:3]';
%! B = rand (3);
%! C = {'a', 'XX'; 'b', 'YY'; 'c', 'ZZ'};
%! D = {"A"; "B"; "C"};
%! T1 = table (A, B, C, D);
%! T2 = splitvars (T1);
%! assert (T2.Properties.VariableNames, ...
%!         {'A', 'B_1', 'B_2', 'B_3', 'C_1', 'C_2', 'D'});
%!test
%! A = [1:3]';
%! B = rand (3);
%! C = {'a', 'XX'; 'b', 'YY'; 'c', 'ZZ'};
%! D = {"A"; "B"; "C"};
%! T1 = table (A, B, C, D);
%! T2 = addvars (T1, table ([5; 5; 5]));
%! assert (size (T2.Var5), [3, 1]);
%! T3 = splitvars (T2);
%! assert (T3.Properties.VariableNames, ...
%!         {'A', 'B_1', 'B_2', 'B_3', 'C_1', 'C_2', 'D', 'Var1'});
%! assert (size (T3.Var1), [3, 1]);
%!test
%! A = [1:3]';
%! B = rand (3);
%! C = {'a', 'XX'; 'b', 'YY'; 'c', 'ZZ'};
%! D = {"A"; "B"; "C"};
%! T1 = table (A, B, C, D);
%! T2 = addvars (T1, table ([5, 6; 5, 6; 5, 6]));
%! assert (size (T2.Var5), [3, 1]);
%! T3 = splitvars (T2);
%! assert (T3.Properties.VariableNames, ...
%!         {'A', 'B_1', 'B_2', 'B_3', 'C_1', 'C_2', 'D', 'Var1'});
%! assert (size (T3.Var1), [3, 2]);
%!test
%! A = [1:3]';
%! B = rand (3);
%! C = {'a', 'XX'; 'b', 'YY'; 'c', 'ZZ'};
%! D = {"A"; "B"; "C"};
%! T1 = table (A, B, C, D);
%! A = [5; 5; 5];
%! T2 = addvars (T1, table (A));
%! T3 = splitvars (T2);
%! assert (T3.Properties.VariableNames, ...
%!         {'A', 'B_1', 'B_2', 'B_3', 'C_1', 'C_2', 'D', 'Var5_A'});
%!test
%! A = [1:3]';
%! B = rand (3);
%! C = {'a', 'XX'; 'b', 'YY'; 'c', 'ZZ'};
%! D = {"A"; "B"; "C"};
%! T1 = table (A, B, C, D);
%! A = [5; 5; 5];
%! T2 = addvars (T1, table ([5, 6; 5, 6; 5, 6]), table (A));
%! T3 = splitvars (T2);
%! assert (T3.Properties.VariableNames, ...
%!         {'A', 'B_1', 'B_2', 'B_3', 'C_1', 'C_2', 'D', 'Var1', 'Var6_A'});
%!test
%! load patients
%! Personal_Data = table (Gender, Age);
%! BMI_Data = table (Height, Weight);
%! BloodPressure = table (Systolic, Diastolic);
%! T1 = table (LastName, Personal_Data, BMI_Data, BloodPressure);
%! T2 = splitvars (T1, 'BloodPressure');
%! assert (T2.Properties.VariableNames, ...
%!         {'LastName', 'Personal_Data', 'BMI_Data', 'Systolic', 'Diastolic'});
%!test
%! load patients
%! Personal_Data = table (Gender, Age);
%! BMI_Data = table (Height, Weight);
%! BloodPressure = table (Systolic, Diastolic);
%! T1 = table (LastName, Personal_Data, BMI_Data, BloodPressure);
%! T2 = splitvars (T1, {'BMI_Data', 'BloodPressure'});
%! assert (T2.Properties.VariableNames, {'LastName', 'Personal_Data', ...
%!         'Height', 'Weight', 'Systolic', 'Diastolic'});
%!test
%! load patients
%! Personal_Data = table (Gender, Age);
%! BMI_Data = table (Height, Weight);
%! BloodPressure = table (Systolic, Diastolic);
%! T1 = table (LastName, Personal_Data, BMI_Data, BloodPressure);
%! T2 = splitvars (T1, [2, 4]);
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', 'Age', ...
%!                                       'BMI_Data', 'Systolic', 'Diastolic'});
%!test
%! load patients
%! Personal_Data = table (Gender, Age);
%! BMI_Data = table (Height, Weight);
%! BloodPressure = table (Systolic, Diastolic);
%! T1 = table (LastName, Personal_Data, BMI_Data, BloodPressure);
%! T2 = splitvars (T1, [false, true, false, true]);
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', 'Age', ...
%!                                       'BMI_Data', 'Systolic', 'Diastolic'});
%!test
%! load patients
%! Personal_Data = [Age, Height, Weight];
%! BloodPressure = [Systolic, Diastolic];
%! T1 = table (LastName, Gender, Personal_Data, BloodPressure);
%! T2 = splitvars (T1, 'BloodPressure', ...
%!                 'NewVariableNames', {'Systolic','Diastolic'});
%! assert (T2.Properties.VariableNames, ...
%!         {'LastName', 'Gender', 'Personal_Data', 'Systolic', 'Diastolic'});
%!test
%! load patients
%! Personal_Data = [Age, Height, Weight];
%! BloodPressure = [Systolic, Diastolic];
%! T1 = table (LastName, Gender, Personal_Data, BloodPressure);
%! T2 = splitvars (T1, {'Personal_Data', 'BloodPressure'}, ...
%!                 'NewVariableNames', {{'Age', 'Height', 'Weight'}, ...
%!                                      {'Systolic', 'Diastolic'}});
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', ...
%!         'Age', 'Height', 'Weight', 'Systolic', 'Diastolic'});
%!test
%! load patients
%! Personal_Data = [Age, Height, Weight];
%! BloodPressure = [Systolic, Diastolic];
%! T1 = table (LastName, Gender, Personal_Data, BloodPressure);
%! new_PD = string ({'Age', 'Height', 'Weight'});
%! T2 = splitvars (T1, {'Personal_Data', 'BloodPressure'}, ...
%!                 'NewVariableNames', {new_PD, {'Systolic', 'Diastolic'}});
%! assert (T2.Properties.VariableNames, {'LastName', 'Gender', ...
%!         'Age', 'Height', 'Weight', 'Systolic', 'Diastolic'});

## Test 'mergevars' method
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, [2, 3]);
%! assert (T2.Properties.VariableNames, {'A', 'Var2', 'D'});
%! assert (isequal (T2.Var2, cat (2, B, C)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, [2, 3], 'NewVariableName', 'Merged');
%! assert (T2.Properties.VariableNames, {'A', 'Merged', 'D'});
%! assert (isequal (T2.Merged, cat (2, B, C)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, [2, 3], 'MergeAsTable', true);
%! assert (T2.Properties.VariableNames, {'A', 'Var2', 'D'});
%! assert (isequal (T2.Var2, table (B, C)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, [2, 3], 'NewVariableName', 'Merged', 'MergeAsTable', 1);
%! assert (T2.Properties.VariableNames, {'A', 'Merged', 'D'});
%! assert (isequal (T2.Merged, table (B, C)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, {"A", "B"});
%! assert (T2.Properties.VariableNames, {'Var1', 'C', 'D'});
%! assert (isequal (T2.Var1, cat (2, A, B)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, {"A", "B"}, 'NewVariableName', 'Merged');
%! assert (T2.Properties.VariableNames, {'Merged', 'C', 'D'});
%! assert (isequal (T2.Merged, cat (2, A, B)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, {"A", "B"}, 'MergeAsTable', true);
%! assert (T2.Properties.VariableNames, {'Var1', 'C', 'D'});
%! assert (isequal (T2.Var1, table (A, B)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! T2 = mergevars (T1, {"A", "B"}, 'NewVariableName', 'Merged', ...
%!                                 'MergeAsTable', true);
%! assert (T2.Properties.VariableNames, {'Merged', 'C', 'D'});
%! assert (isequal (T2.Merged, table (A, B)), true);

## Test 'convertvars' method
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! assert (isa (T1.A, "numeric"), true);
%! assert (isa (T1.B, "numeric"), true);
%! T2 = convertvars (T1, {"A", "B"}, "string");
%! assert (isa (T2.A, "string"), true);
%! assert (isa (T2.B, "string"), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! assert (isa (T1.D, "string"), true);
%! T2 = convertvars (T1, 4, "cellstr");
%! assert (iscellstr (T2.D), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! assert (isa (T1.D, "string"), true);
%! T2 = convertvars (T1, [1:3], @(x) sqrt (x));
%! assert (isequal (T2.A, sqrt (A)), true);
%! assert (isequal (T2.B, sqrt (B)), true);
%! assert (isequal (T2.C, sqrt (C)), true);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = string ({"a"; "b"; "c"});
%! T1 = table (A, B, C, D);
%! assert (isa (T1.D, "string"), true);
%! T2 = convertvars (T1, [1:3], @(x) [x, x, x]);
%! assert (size (T2.A, 2), 3);
%! assert (size (T2.B, 2), 3);
%! assert (size (T2.C, 2), 3);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = {"a"; "b"; "c"};
%! T1 = table (A, B, C, D);
%! T2 = convertvars (T1, "D", @(x) cellstr (upper (char (x))));
%! assert (T2.D, {"A"; "B"; "C"});

## Test 'rows2vars' method
%!test
%! load patients
%! T1 = table (LastName, Gender, Age, Height, Weight);
%! T2 = rows2vars (T1);
%! assert (size (T1, 2), size (T2, 1));
%! assert (size (T1, 1) + 1, size (T2, 2));
%! assert (T2.OriginalVariableNames, ...
%!         {"LastName"; "Gender"; "Age"; "Height"; "Weight"});
%! assert (T2.Var1, {"Smith"; "Male"; 38; 71; 176});
%!test
%! load patients
%! T1 = table (Gender, Age, Height, Weight, "RowNames", LastName);
%! T2 = rows2vars (T1);
%! assert (T2.OriginalVariableNames, {"Gender"; "Age"; "Height"; "Weight"});
%! assert (T2.Smith, {"Male"; 38; 71; 176});
%! assert (T2.Johnson, {"Male"; 43; 69; 163});
%! assert (T2.Williams, {"Female"; 38; 64; 131});
%!test
%! load patients
%! T1 = table (LastName, Gender, Age, Height, Weight);
%! T2 = rows2vars (T1, "VariableNamesSource", "LastName");
%! assert (T2.OriginalVariableNames, {"Gender"; "Age"; "Height"; "Weight"});
%! assert (T2.Smith, {"Male"; 38; 71; 176});
%! assert (T2.Johnson, {"Male"; 43; 69; 163});
%! assert (T2.Williams, {"Female"; 38; 64; 131})
%!test
%! load patients
%! T1 = table (LastName, Gender, Age, Height, Weight);
%! T2 = rows2vars (T1, "DataVariables", {"LastName", "Gender", "Age"});
%! assert (size (T2, 1), 3);
%! assert (size (T1, 1) + 1, size (T2, 2));
%! assert (T2.OriginalVariableNames, {"LastName"; "Gender"; "Age"});
%! assert (T2.Var1, {"Smith"; "Male"; 38});
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! T1 = table (A, B, C);
%! T2 = rows2vars (T1);
%! assert (class (T2.Var1), "double");
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! D = {"a"; "b"; "c"};
%! T1 = table (A, B, C, D);
%! T2 = rows2vars (T1);
%! assert (class (T2.Var1), "cell");
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! T1 = table (A, B, C);
%! T2 = rows2vars (T1, "VariableNamesSource", "A");
%! assert (size (T2), [2, 4]);
%! assert (T2.Properties.VariableNames(1), {"OriginalVariableNames"});
%! assert (T2.Properties.VariableNames(2:4), {"x1", "x2", "x3"});
%! assert (T2.x1, [5; 3.14]);
%!test
%! A = [1:3]';
%! B = [5; 11; 12];
%! C = [3.14; 2.72; 1.37];
%! T1 = table (A, B, C);
%! T2 = rows2vars (T1, "VariableNamesSource", "A", ...
%!                     "VariableNamingRule", "preserve");
%! assert (size (T2), [2, 4]);
%! assert (T2.Properties.VariableNames(1), {"OriginalVariableNames"});
%! assert (T2.Properties.VariableNames(2:4), {"1", "2", "3"});
%! assert (T2.('1'), [5; 3.14]);

## Test 'stack' method
%!test
%! Test1 = [93; 57; 87; 89];
%! Test2 = [89; 77; 92; 86];
%! Test3 = [95; 62; 89; 91];
%! U = table (Test1, Test2, Test3);
%! S = stack (U, 1:3);
%! assert (size (S), [12, 2]);
%! assert (class (S.Test1_Test2_Test3_Indicator), "categorical");
%! assert (cellstr (S.Test1_Test2_Test3_Indicator), ...
%!         repmat ({"Test1"; "Test2"; "Test3"}, 4, 1));
%! assert (S.Test1_Test2_Test3, [Test1';Test2';Test3'](:));
%!test
%! Test1 = [93; 57; 87; 89];
%! Test2 = [89; 77; 92; 86];
%! Test3 = [95; 62; 89; 91];
%! U = table (Test1, Test2, Test3);
%! [S, idx] = stack (U, 1:2);
%! assert (idx, [1; 1; 2; 2; 3; 3; 4; 4]);
%! assert (cellstr (S.Test1_Test2_Indicator), ...
%!         repmat ({"Test1"; "Test2"}, 4, 1));
%! assert (S.Test3, repelem (Test3, 2, 1));
%!test
%! Test1 = [93; 57; 87; 89];
%! Test2 = [89; 77; 92; 86];
%! Test3 = [95; 62; 89; 91];
%! U = table (Test1, Test2, Test3);
%! S = stack (U, 1:3, 'NewDataVariableName', 'NewData', ...
%!                    'IndexVariableName', 'Index');
%! assert (size (S), [12, 2]);
%! assert (class (S.Index), "categorical");
%! assert (cellstr (S.Index), repmat ({"Test1"; "Test2"; "Test3"}, 4, 1));
%! assert (S.NewData, [Test1';Test2';Test3'](:));
%!test
%! Test1 = [93; 57; 87; 89];
%! Test2 = [89; 77; 92; 86];
%! Test3 = [95; 62; 89; 91];
%! Test4 = [95; 62; 89; 91];
%! U = table (Test1, Test2, Test3, Test4);
%! S = stack (U, 1:2, 'ConstantVariables', "Test4");
%! assert (S.Properties.VariableNames, ...
%!         {"Test4", "Test1_Test2_Indicator", "Test1_Test2"});
%!test
%! Test1 = [93; 57; 87; 89];
%! Test2 = [89; 77; 92; 86];
%! Test3 = [95; 62; 89; 91];
%! Test4 = [95; 62; 89; 91];
%! U = table (Test1, Test2, Test3, Test4);
%! S = stack (U, {"Test1", "Test4"}, 'ConstantVariables', "Test2");
%! assert (S.Properties.VariableNames, ...
%!         {"Test2", "Test1_Test4_Indicator", "Test1_Test4"});
%!test
%! Test1 = [93; 57; 87; 89];
%! Test2 = [89; 77; 92; 86];
%! Test3 = [95; 62; 89; 91];
%! Test4 = [95; 62; 89; 91];
%! U = table (Test1, Test2, Test3, Test4);
%! S = stack (U, {"Test1", "Test4"}, 'ConstantVariables', "Test2", ...
%!            'NewDataVariableName', 'NewData', 'IndexVariableName', 'Index');
%! assert (S.Properties.VariableNames, ...
%!         {"Test2", "Index", "NewData"});

## Test 'unstack' method
%! Storm = [3; 3; 1; 3; 1; 1; 4; 2; 4; 2; 4; 2];
%! Town = categorical ({'Natick'; 'Worcester'; 'Natick'; 'Boston'; ...
%!                      'Boston'; 'Worcester'; 'Boston'; 'Natick'; ...
%!                      'Worcester'; 'Worcester'; 'Natick'; 'Boston'});
%! Snowfall = [0; 3; 5; 5; 9; 10; 12; 13; 15; 16; 17; 21];
%! S = table (Storm, Town, Snowfall);
%! U = unstack (S, 'Snowfall', 'Town');
%! assert (U.Storm, [3; 1; 4; 2]);
%! assert (U.Properties.VariableNames, {'Storm', 'Boston', 'Natick', 'Worcester'});





## Reinitialize variables before testing input validation
%! LastName = {"Sanchez"; "Johnson"; "Li"; "Diaz"; "Brown"};
%! Age = [38; 43; 38; 40; 49];
%! Smoker = logical ([1; 0; 1; 0; 1]);
%! Height = [71; 69; 64; 67; 64];
%! Weight = [176; 163; 131; 133; 119];
%! BloodPressure = [124, 93; 109, 77; 125, 83; 117, 75; 122, 80];
%! tblA = table (Age, Height, Weight, BloodPressure, 'RowNames', LastName);
%! tblB = table (LastName, Age, Height, Weight, BloodPressure);

## Test input validation for constructor
%!error <table: 'VariableNames' must be either a cell array of character vectors or a string array.> ...
%! table (Age, Smoker, "VariableNames", {2, 3});
%!error <table: 'VariableNames' must be either a cell array of character vectors or a string array.> ...
%! table (Age, Smoker, "VariableNames", [2, 3]);
%!error <table: 'VariableNames' must be either a cell array of character vectors or a string array.> ...
%! table (Age, Smoker, "VariableNames", [true, true]);
%!error <table: 'RowNames' must be either a cell array of character vectors or a string array.> ...
%! table (Age, Smoker, "RowNames", {2, 3});
%!error <table: 'RowNames' must be either a cell array of character vectors or a string array.> ...
%! table (Age, Smoker, "RowNames", [2, 3]);
%!error <table: 'RowNames' must be either a cell array of character vectors or a string array.> ...
%! table (Age, Smoker, "RowNames", [true, false]);
%!error <table: 'DimensionNames' must be either a two-element cell array of character vectors or a two-element string array.> ...
%! table (Age, Smoker, "DimensionNames", {2, 3});
%!error <table: 'DimensionNames' must be either a two-element cell array of character vectors or a two-element string array.> ...
%! table (Age, Smoker, "DimensionNames", [2, 3]);
%!error <table: 'DimensionNames' must be either a two-element cell array of character vectors or a two-element string array.> ...
%! table (Age, Smoker, "DimensionNames", [true, false]);
%!error <table: 'DimensionNames' must be either a two-element cell array of character vectors or a two-element string array.> ...
%! table (Age, Smoker, "DimensionNames", {"A", "B", "C"});
%!error <table: duplicate dimension and variable name: 'Variables'> ...
%! table (1, 'VariableNames', {'Variables'});
%!error <table: 'VariableTypes' must be a cellstring array of the same number of elements as defined in SZ> ...
%! table ("Size", [4, 2], "VariableTypes", {"A", "B", "C"});
%!error <table: 'VariableTypes' must be a cellstring array of the same number of elements as defined in SZ> ...
%! table ("Size", [4, 3], "VariableTypes", ["A", "B", "C"]);
%!error <table: 'VariableTypes' must be a cellstring array of the same number of elements as defined in SZ> ...
%! table ("Size", [4, 3], "VariableTypes", {1, 2, 3});
%!error <table: inconsistent number of 'VariableNames' and 'VariableTypes'.> ...
%! table ("Size", [4, 3], "VariableTypes", {"double", "double", "logical"}, ...
%!        "VariableNames", {"A", "B"});
%!error <table: inconsistent number of 'RowNames' and rows defined in SZ.> ...
%! table ("Size", [4, 3], "VariableTypes", {"double", "double", "logical"}, ...
%!        "RowNames", {"A", "B", "C"});
%!error <table: 'timetable' variable type not supported yet.> ...
%! table ("Size", [4, 3], "VariableTypes", {"double", "double", "timetable"}, ...
%!        "VariableNames", {"A", "B", "C"});
%!error <table: 'timetable' variable type not supported yet.> ...
%! table ("Size", [4, 3], "VariableTypes", {"double", "double", "timetable"}, ...
%!        "RowNames", {"A", "B", "C", "D"});
%!error <table: 'timetable' variable type not supported yet.> ...
%! table ("Size", [4, 3], "VariableTypes", {"double", "double", "timetable"});
%!error <table: duplicate variable names: Age> table (Age, Age);
%!error <table: duplicate variable names: Age, Height> ...
%! table (Age, Age, Height, Height);
%!error <table: inconsistent number of variable names> ...
%! table (Age, Height, "VariableNames", {"A"})
%!error <table: variable values must not have more than 2 dimensions: input 1 'A' has 3.> ...
%! table (ones (5, 5, 5), Height, "VariableNames", {"A", "B"});
%!error <table: variable values must not have more than 2 dimensions: input 2 'B' has 3.> ...
%! table (Height, ones (5, 5, 5), "VariableNames", {"A", "B"});
%!error <table: inconsistent sizes between variables: var 'A' has 1 rows; var 'B' has 5 rows.> ...
%! table (struct ("age", Age), Height, "VariableNames", {"A", "B"});
%!error <table: inconsistent sizes between variables: var 'A' has 5 rows; var 'B' has 1 rows.> ...
%! table (Height, struct ("age", Age), "VariableNames", {"A", "B"});
%!error <table.table2array: table cannot be concatenated into a matrix due to incompatible variable types.> ...
%! table2array (table (Height, {1; 2; 3; 4; 5}, "VariableNames", {"A", "B"}));
%!error <table.table2struct: wrong number of input arguments.> ...
%! table2struct (T, "ToScalar");
%!error <table.table2struct: wrong optional input argument.> ...
%! table2struct (T, "Scalar", 1);
%!error <table: elements in 'RowNames' must be unique.> ...
%! table ("Size", [4, 2], "VariableTypes", {"double", "double"}, ...
%!        "RowNames", {"A", "B", "B", "D"});

## Test input validation for **summary information** methods
%!error <table.head: K must be a positive integer scalar value.> ...
%! head (T, 1.5);
%!error <table.head: K must be a positive integer scalar value.> ...
%! head (T, -2);
%!error <table.head: invalid number of output arguments.> ...
%! [out1, out2] = head (T, 2);
%!error <table.tail: K must be a positive integer scalar value.> ...
%! tail (T, 1.5);
%!error <table.tail: K must be a positive integer scalar value.> ...
%! tail (T, -2);
%!error <table.tail: invalid number of output arguments.> ...
%! [out1, out2] = tail (T, 2);

## Test input validation for 'sortrows' method
%!error <table.sortrows: 'MissingPlacement' parameter can be either 'auto', 'first', or 'last'.> ...
%! sortrows (tblA, "MissingPlacement", "param");
%!error <table.sortrows: 'ComparisonMethod' parameter can be either 'auto', 'real', or 'abs'.> ...
%! sortrows (tblA, "ComparisonMethod", "param");
%!error <table.sortrows: invalid number of input arguments.> ...
%! sortrows (tblA, [], "ascend", "param");
%!error <table.sortrows: invalid value for DIRECTION argument.> ...
%! sortrows (tblA, [], "aaascend");
%!error <table.sortrows: DIRECTION must be a scalar input when 'RowNames' or 'rowDimNames' are selected.> ...
%! sortrows (tblA, "RowNames", {"ascend", "ascend"});
%!error <table.sortrows: DIRECTION must be a scalar input when 'RowNames' or 'rowDimNames' are selected.> ...
%! sortrows (tblA, "Row", {"ascend", "ascend"});
%!error <table.sortrows: logical indexing vector does not match table width.> ...
%! sortrows (tblA, [true, true, false]);
%!error <table.sortrows: invalid size for DIRECTION argument.> ...
%! sortrows (tblA, "Age", {"ascend", "ascend"});
%!error <table.sortrows: numerical indexing must be a vector of nonzero integers.> ...
%! sortrows (tblA, [1, 0, 3]);
%!error <table.sortrows: numerical index exceeds table dimensions.> ...
%! sortrows (tblA, [1, 6, 3]);
%!error <table.sortrows: invalid size for DIRECTION argument.> ...
%! sortrows (tblA, [1, 3, 2], {"ascend", "ascend"});
%!error <table.sortrows: VARS indexes non-existing variable names.> ...
%! sortrows (tblA, {"Age", "whatever"});
%!error <table.sortrows: invalid size for DIRECTION argument.> ...
%! sortrows (tblA, {"Age", "Height", "Weight"}, {"ascend", "ascend"});
%!error <table.sortrows: DIRECTION must be a scalar input when variables are indexed with a 'vartype' object.> ...
%! sortrows (tblA, vartype ("numeric"), {"ascend", "ascend"});
%!error <table.sortrows: cannot sort variables of 'cell' type.> ...
%! sortrows (table ({5; 4; 3}));
%!error <table.sortrows: cannot sort variables of 'struct' type.> ...
%! sortrows (table ([struct("s", 4); struct("s", 5); struct("s", 6)]));
%!error <table.sortrows: cannot sort nested tables with mixed data types.> ...
%! sortrows (table (Age, table (Age, LastName), "RowNames", LastName))

## Test input validation for 'unique' method
%!error <table.unique: too many input arguments.> unique (tblA, 1, 2);
%!error <table.unique: invalid option 'some'.> unique (tblA, "some");
%!error <table.sortrows: cannot sort variables of 'cell' type.> ...
%! unique (table ({2; 2; 3}), "sorted");
%!error <table.sortrows: cannot sort variables of 'struct' type.> ...
%! unique (table (struct ("a", {2; 2; 3})), "sorted");
%!error <table.sortrows: cannot sort nested tables with mixed data types.> ...
%! unique (table (table (Age, LastName)), "sorted");

## Test input validation for 'topkrows' method
%!error <table.topkrows: K must be a nonnegative integer scalar.> ...
%! topkrows (tblA, -1)
%!error <table.topkrows: K must be a nonnegative integer scalar.> ...
%! topkrows (tblA, 2.5)

## Test input validation for 'addvars' method
%!error <table.addvars: cannot use both 'After' and 'Before' options.> ...
%! addvars (tblA, Smoker, 'After', 1, 'Before', 2);
%!error <table.addvars: LOCATION must index a single variable.> ...
%! addvars (tblA, Smoker, 'After', [true, false, false, true]);
%!error <table.addvars: LOCATION must be either a scalar integer, a character vector, or a logical vector indexing a single table variable.> ...
%! addvars (tblA, Smoker, 'After', [1, 2]);
%!error <table.addvars: NEWNAMES does not match the number of new variables.> ...
%! addvars (tblA, Smoker, 'NewVariableNames', {'A', 'B'});
%!error <table.addvars: NEWNAMES contains duplicate names.> ...
%! addvars (tblA, Smoker, Smoker, 'NewVariableNames', {'A', 'A'});
%!error <table.addvars: new variable name 'Height' already exists.> ...
%! addvars (tblA, Smoker, 'NewVariableNames', {'Height'});
%!error <table.addvars: new variable names 'Height', 'Weight' already exist.> ...
%! addvars (tblA, Smoker, Smoker, 'NewVariableNames', {'Height', 'Weight'});

## Test input validation for 'renamevars' method
%!error <table.renamevars: too few input arguments.> ...
%! renamevars (tblA, {"Age", "Smoker"});
%!error <table.renamevars: too few input arguments.> ...
%! renamevars (tblA, {"Age"}, {});
%!error <table.renamevars: too few input arguments.> ...
%! renamevars (tblA, {}, {"NewName"});
%!error <table.renamevars: NEWNAMES must be either a character vector, a cell array of character vectors, or a string array.> ...
%! renamevars (tblA, {"Age", "Smoker"}, {"Age", 4});
%!error <table.renamevars: NEWNAMES contains duplicate names.> ...
%! renamevars (tblA, {"Age", "Smoker"}, {"Age", "Age"});
%!error <table.renamevars: cannot index non-existing variable: 'Smoker'.> ...
%! renamevars (tblA, {"Age", "Smoker"}, {"Age", "User"});
%!error <table.renamevars: number of names in NEWNAMES do not match the selected variables specified by VARS.> ...
%! renamevars (tblA, {"Age", "Height"}, {"Age", "Smoker", "Height"});
%!error <table.renamevars: newly assigned variable name already exists.> ...
%! renamevars (tblA, {"Age", "Height"}, {"Age", "Weight"});

## Test input validation for 'movevars' method
%!error <table.movevars: too few input arguments.> movevars (tblA);
%!error <table.movevars: too few input arguments.> movevars (tblA, {});
%!error <table.movevars: cannot use both 'After' and 'Before' options.> ...
%! movevars (tblA, 1, "After", "Height", "Before", "Weight");
%!error <table.movevars: LOCATION must index a single variable.> ...
%! movevars (tblA, 1, "After", [true, true, false, false]);
%!error <table.movevars: LOCATION must be either a scalar integer, a character vector, or a logical vector indexing a single table variable.> ...
%! movevars (tblA, 1, "After", [1, 2]);
%!error <table.movevars: LOCATION must be either a scalar integer, a character vector, or a logical vector indexing a single table variable.> ...
%! movevars (tblA, 1, "After", {"Height"});
%!error <table.movevars: LOCATION does not index an existing variable.> ...
%! movevars (tblA, 1, "After", "Smoker");
%!error <table.movevars: cannot index non-existing variable: 'Smoker'.> ...
%! movevars (tblA, "Smoker", "After", 2);
%!error <table.movevars: LOCATION variable cannot be moved.> ...
%! movevars (tblA, {"Age", "Height"}, "After", 2);
%!error <table.movevars: LOCATION variable cannot be moved.> ...
%! movevars (tblA, {"Height", "Weight"}, "Before", "Height");

## Test input validation for 'removevars' method
%!error <table.removevars: too few input arguments.> removevars (tblA);
%!error <table: variable index must be a vector.> removevars (tblA, ones (2));
%!error <table: variable logical index does not match table width.> ...
%! removevars (tblA, [true, true, false]);
%!error <table: variable index out of bounds: requested index 5; table has 4 variables.> ...
%! removevars (tblA, [1, 5]);
%!error <table: variable index out of bounds: requested index 7; table has 4 variables.> ...
%! removevars (tblA, [1, 2, 7]);
%!error <table: no such variable in table: 'Smoker'.> ...
%! removevars (tblA, "Smoker");
%!error <table: no such variables in table: 'Smoker', 'Health'.> ...
%! removevars (tblA, {"Smoker", "Health"});
%!error <table: unsupported variable indexing operand type: 'cell'.> ...
%! removevars (tblA, {1});
%!error <table: unsupported variable indexing operand type: 'struct'.> ...
%! removevars (tblA, struct ("A", 1));

## Test input validation for 'splitvars' method
%!error <table.splitvars: too many input arguments.> splitvars (tblA, 1, 2, 3, 4);
%!error <table.splitvars: invalid input for 'NewVariableNames'.> ...
%! splitvars (table ([5, 6; 5, 6; 5, 6]), 1, 'NewVariableNames', {1})
%!error <table.splitvars: invalid input for 'NewVariableNames'.> ...
%! splitvars (table ([5, 6; 5, 6; 5, 6]), 1, 'NewVariableNames', 1)
%!error <table.splitvars: invalid input for 'NewVariableNames'.> ...
%! splitvars (table ([5, 6; 5, 6; 5, 6]), 1, 'NewVariableNames', "new_name")
%!error <table.splitvars: invalid input for 'NewVariableNames'.> ...
%! splitvars (table ([5, 6; 5, 6; 5, 6], ones (3, 2)), ":", ...
%!            'NewVariableNames', {{"A", "B"}, {"new_name", 1}})
%!error <table.splitvars: wrong number of 'NewVariableNames'.> ...
%! splitvars (table ([5, 6; 5, 6; 5, 6], ones (3, 2)), ":", ...
%!            'NewVariableNames', {{"A", "B"}, {"C", "D", "E"}})

## Test input validation for 'mergevars' method
%!error <table.mergevars: too few input arguments.> mergevars (tblA);
%!error <table.mergevars: invalid input for 'MergeAsTable'.> ...
%! mergevars (tblA, {'Height', 'Weight'}, 'MergeAsTable', 'on');
%!error <table.mergevars: invalid input for 'MergeAsTable'.> ...
%! mergevars (tblA, {'Height', 'Weight'}, 'MergeAsTable', 2);
%!error <table.mergevars: invalid input for 'MergeAsTable'.> ...
%! mergevars (tblA, {'Height', 'Weight'}, 'MergeAsTable', [true, true]);
%!error <table.mergevars: invalid input for 'NewVariableName'.> ...
%! mergevars (tblA, {'Height', 'Weight'}, 'NewVariableName', 2)
%!error <table.mergevars: assigned 'NewVariableName' already exists.> ...
%! mergevars (tblA, {'Height', 'Weight'}, 'NewVariableName', 'Age');
%!error <table.mergevars: selected variables cannot be merged into a multicolumn variable due to incompatible variable types.> ...
%! mergevars (addvars (tblA, LastName), {'Height', 'LastName'});

## Test input validation for 'convertvars' method
%!error <table.mergevars: too few input arguments.> convertvars (tblA);
%!error <table.mergevars: too few input arguments.> ...
%! convertvars (tblA, "Height");
%!error <table.convertvars: DATATYPE must be a character vector.> ...
%! convertvars (tblA, "Height", ["c","h";"a","r"]);
%!error <table.convertvars: DATATYPE must be either a character vector or a function handle; got a 'cell'.> ...
%! convertvars (tblA, "Height", {"char"});
%!error <table.convertvars: DATATYPE must be either a character vector or a function handle; got a 'double'.> ...
%! convertvars (tblA, "Height", 25);
%!error <table.convertvars: specified DATATYPE conversion cannot be applied on selected variable 'Height'.> ...
%! convertvars (tblA, "Height", "struct");
%!error <table.convertvars: specified DATATYPE conversion on 'Height' does not return the appropriate amount of rows.> ...
%! convertvars (tblA, "Height", @(x) sum (x));

## Test input validation for  'rows2vars' method
%!error <table.rows2vars: 'DataVariables' index a non-existing variable: 'Some'.> ...
%! rows2vars (tblA, "DataVariables", "Some");
%!error <table.rows2vars: 'VariableNamesSource' must index a single variable.> ...
%! rows2vars (tblA, "VariableNamesSource", {"LastName", "Age"});
%!error <table.rows2vars: 'VariableNamesSource' indexes a non-existing variable: 'Some'.> ...
%! rows2vars (tblA, "VariableNamesSource", {"Some"});
%!error <table.rows2vars: the number of names taken from the variable specified in 'VariableNamesSource' does not match the number of rows in input table.> ...
%! rows2vars (tblA, "VariableNamesSource", {"Age"});
%!error <table.rows2vars: 'VariableNamesSource' cannot specify a variable that is also specified by 'DataVariables'.> ...
%! rows2vars (table (LastName, Age), "DataVariables", "LastName", "VariableNamesSource", "LastName");
%!error <table.rows2vars: invalid input for 'VariableNamingRule'.> ...
%! rows2vars (tblA, "VariableNamingRule", "somerule");
%!error <table.rows2vars: input table must not contain nested tables.> ...
%! rows2vars (table (tblA, LastName));
%!error <table.rows2vars: input table must not contain multicolumn variables.> ...
%! rows2vars (tblA);

## Test input validation for  'stack' method
%!error <table.stack: too few input arguments.> stack (tblA);
%!error <table.stack: VARS index a non-existing variable: 'Some'.> ...
%! stack (tblA, "Some");
%!error <table.stack: 'ConstantVariables' index a non-existing  variable: 'Some'.> ...
%! stack (tblA, 1:3, "ConstantVariables", "Some");
%!error <table.stack: 'ConstantVariables' cannot contain any variables to be stacked as specified by VARS.> ...
%! stack (tblA, 1:3, "ConstantVariables", "Weight");
%!error <table.stack: 'NewDataVariableName' must be either a character vector, or a cellstring or string scalar.> ...
%! stack (tblA, 1:3, "NewDataVariableName", 3);
%!error <table.stack: 'IndexVariableName' must be either a character vector, or a cellstring or string scalar.> ...
%! stack (tblA, 1:3, "IndexVariableName", 3);

## Test input validation for  'unstack' method
%!error <table.unstack: too few input arguments.> unstack (tblA);
%!error <table.unstack: too few input arguments.> unstack (tblA, 'Height');
%!error <table.unstack: too few input arguments.> unstack (tblA, [], 'Height');
%!error <table.unstack: VARS index a non-existing variable: 'some'.> ...
%! unstack (tblA, 'some', 'Height');
%!error <table.unstack: VARS must not index nested tables.> ...
%! unstack (table (table (Age), Smoker, Height), 'Var1', 'Height');
%!error <table.unstack: IVAR must index a single variable.> ...
%! unstack (tblA, 'Height', {'Smoker', 'Age'});
%!error <table.unstack: IVAR indexes a non-existing variable: 'some'.> ...
%! unstack (tblA, 'Height', 'some');
%!error <table.unstack: IVAR must index a single column variable.> ...
%! unstack (tblA, 'Height', 'BloodPressure');
%!error <table.unstack: IVAR cannot be any of the variables to be unstacked as specified by VARS.> ...
%! unstack (tblA, 'Height', 'Height');
%!error <table.unstack: IVAR indexes a variable of invalid type: 'cell'.> ...
%! unstack (table ({4;5;6;7;8}, Smoker, Height), 'Height', 'Var1');
%!error <table.unstack: 'ConstantVariables' index a non-existing variable: 'some'.> ...
%! unstack (tblA, 'Height', 'Age', 'ConstantVariables', 'some');
%!error <table.unstack: 'ConstantVariables' cannot contain any variables to be unstacked as specified by VARS.> ...
%! unstack (tblA, 'Height', 'Age', 'ConstantVariables', 'Height');
%!error <table.unstack: 'ConstantVariables' cannot contain the indicator variable as specified by IVAR.> ...
%! unstack (tblA, 'Height', 'Age', 'ConstantVariables', 'Age');
%!error <table.unstack: 'GroupingVariables' index a non-existing variable: 'some'.> ...
%! unstack (tblA, 'Height', 'Age', 'GroupingVariables', 'some');
%!error <table.unstack: 'GroupingVariables' cannot contain any variables to be unstacked as specified by VARS.> ...
%! unstack (tblA, 'Height', 'Age', 'GroupingVariables', 'Height');
%!error <table.unstack: 'GroupingVariables' cannot contain the indicator variable as specified by IVAR.> ...
%! unstack (tblA, 'Height', 'Age', 'GroupingVariables', 'Age');
%!warning <table.unstack: 'GroupingVariables' index a variable of invalid type: 'Var1', which is ignored.> ...
%! unstack (table ({4;5;6;7;8}, Smoker, Height, Age), 'Height', 'Age', 'GroupingVariables', 'Var1');
%!error <table.unstack: 'ConstantVariables' cannot contain any grouping variables as specified by 'GroupingVariables'.> ...
%! unstack (tblA, 'BloodPressure', 'Height', 'ConstantVariables', 'Age', 'GroupingVariables', 'Age');
%!error <table.unstack: 'NewDataVariableNames' must be either a cell array of character vectors, or a string array.> ...
%! unstack (tblA, 'Height', 'Age', 'NewDataVariableNames', [1:5]);
%!error <table.unstack: 'NewDataVariableNames' do not match the number of unique values in the indicator variable.> ...
%! unstack (tblA, 'Height', 'Age', 'NewDataVariableNames', {"A","B","C"});
%!error <table.unstack: 'AggregationFunction' must be a function handle.> ...
%! unstack (tblA, 'Height', 'Age', 'AggregationFunction', 1);
%!error <table.unstack: 'AggregationFunction' must be a function handle.> ...
%! unstack (tblA, 'Height', 'Age', 'AggregationFunction', 'isnumeric');
%!error <table.unstack: invalid input for 'VariableNamingRule'.> ...
%! unstack (tblA, {'Weight', 'Height'}, 'Age', 'VariableNamingRule', 'somerule');


################################################################################
##                           ** Missing Values **                             ##
################################################################################
##                             Available Methods                              ##
##                                                                            ##
## 'anymissing'       'ismissing'        'rmmissing'        'fillmissing'     ##
## 'standardizeMissing'                                                       ##
##                                                                            ##
################################################################################

## Test 'anymissing' method
%!test
%! T = table (categorical ({'1';'2';'';'4'}));
%! assert (anymissing (T), true);
%!test
%! T = table (categorical ({'1';'2';'3';'4'}));
%! assert (anymissing (T), false);
%!test
%! T = table (calyears ([1; 2; NaN; 4]));
%! assert (anymissing (T), true);
%!test
%! T = table (calyears ([1; 2; 3; 4]));
%! assert (anymissing (T), false);
%!test
%! T = table (days ([1; 2; NaN; 4]));
%! assert (anymissing (T), true);
%!test
%! T = table (days ([1; 2; 3; 4]));
%! assert (anymissing (T), false);
%!test
%! T = table (string ([1; 2; NaN; 4]));
%! assert (anymissing (T), true);
%!test
%! T = table (string ([1; 2; 3; 4]));
%! assert (anymissing (T), false);
%!test
%! T = table ({'1'; '2'; ''; '4'});
%! assert (anymissing (T), true);
%!test
%! T = table ({'1'; '2'; 'NaN'; '4'});
%! assert (anymissing (T), false);
%!test
%! T = table (['1'; '2'; ' '; '4']);
%! assert (anymissing (T), true);
%!test
%! T = table (['1'; '2'; 'NaN'; '4']);
%! assert (anymissing (T), false);
%!test
%! T = table (['1'; '2'; 'N'; '4']);
%! assert (anymissing (T), false);

## Test 'ismissing' method
%!test
%! TF = ismissing (table (['   '; ' 2 '; 'NaN'; '4  ']), ' 2');
%! assert (TF, [false; true; false; false]);
%!test
%! TF = ismissing (table (['   '; ' 2 '; 'NaN'; '4  ']), '2');
%! assert (TF, [false; false; false; false]);
%!test
%! TF = ismissing (table (['   '; '2  '; 'NaN'; '4  ']), '2');
%! assert (TF, [false; true; false; false]);
%!test
%! TF = ismissing (table (['   '; ' 2 '; 'NaN'; '4  ']));
%! assert (TF, [true; false; false; false]);
%!test
%! TF = ismissing (table ({'1'; '2'; ''; '4'}));
%! assert (TF, [false; false; true; false]);
%!test
%! TF = ismissing (table ({'1'; '2'; ''; '4'}), 'OutputFormat', 'tabular');
%! assert (class (TF), 'table');
%! assert (TF.Var1, [false; false; true; false]);
%!test
%! TF = ismissing (table ({'1'; '2'; ''; '4'}), {'4'}, 'OutputFormat', 'tabular');
%! assert (class (TF), 'table');
%! assert (TF.Var1, [false; false; false; true]);
%!test
%! TF = ismissing (table ({'1'; '2'; ''; '4'}, string ([1; 2; 3; 4])), {'4', '3'}, 'OutputFormat', 'tabular');
%! assert (class (TF), 'table');
%! assert (TF.Var1, [false; false; false; true]);
%! assert (TF.Var2, [false; false; true; true]);
%!test
%! TF = ismissing (table ({'1'; '2'; ''; '4'}, string ([1; 2; 3; 4])), {'4', '3'});
%! assert (class (TF), 'logical');
%! assert (TF, [false, false; false, false; false, true; true, true]);
%!test
%! TF = ismissing (table (days ([1; 2; NaN; 4]), calweeks ([1; 2; NaN; 4])));
%! assert (TF, [false, false; false, false; true, true; false, false]);


################################################################################
##                       **    Auxiliary Methods    **                        ##
################################################################################
##                             Available Methods                              ##
##                                                                            ##
## 'horzcat'          'iscolumn'         'isempty'          'ismatrix'        ##
## 'isrow'            'isscalar'         'istable'          'isvector'        ##
## 'length'           'ndims'            'numel'            'repelem'         ##
## 'repmat'           'size'             'squeeze'          'vertcat'         ##
##                                                                            ##
################################################################################

%!assert (iscolumn (table ([1; 2; 3])), true)
%!assert (iscolumn (table ([1, 2, 3])), true)
%!assert (iscolumn (table (1, 2, 3)), false)
%!assert (isempty (table ()), true)
%!assert (isempty (table ([])), true)
%!assert (isempty (table (1)), false)
%!assert (ismatrix (table ([])), true)
%!assert (ismatrix (table (1)), true)
%!assert (isrow (table ([1, 2, 3])), true)
%!assert (isrow (table (1, 2, 3)), true)
%!assert (isrow (table ([1; 2; 3])), false)
%!assert (isscalar (table (1)), true)
%!assert (isscalar (table ([1, 2, 3])), true)
%!assert (isscalar (table (1, 2, 3)), false)
%!assert (isscalar (table ([1; 2; 3])), false)
%!assert (istable (table ()), true)
%!assert (isvector (table (1)), true)
%!assert (isvector (table (1, 2, 3)), true)
%!assert (isvector (table ([1, 2, 3])), true)
%!assert (isvector (table ([1; 2; 3])), true)
%!assert (isvector (table ([1; 2], {'a'; 'b'})), false)
%!assert (length (table (1)), 1)
%!assert (length (table ([1; 2; 3])), 3)
%!assert (length (table ([1, 2, 3])), 1)
%!assert (length (table ([1; 2; 3], [2; 3; 4])), 3)
%!assert (length (table ([1; 2], [2; 3], [3; 4], [4; 5])), 4)
%!assert (ndims (table ()), 2)
%!assert (ndims (table ([])), 2)
%!assert (ndims (table ([1, 2, 3, 4])), 2)
%!assert (ndims (table ([1; 2], {'a'; 'b'})), 2)
## 'numel' always return 1 (MATLAB incompatibility)
%!assert (numel (table ()), 1)
%!assert (numel (table (1)), 1)
%!assert (numel (table (1, 2, 3, 4)), 1)
